您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)java基于NIO如何實(shí)現(xiàn)群聊模式,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
具體內(nèi)容如下
Client
package com.qst.chat; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Scanner; public class GroupChatClient { private final int PORT = 9999; private final String HOST = "localhost"; private SocketChannel channel; private static Selector selector; private String name; public GroupChatClient() throws IOException { selector = Selector.open(); // 連接服務(wù)器 channel = SocketChannel.open(new InetSocketAddress(HOST, PORT)); // 設(shè)置非阻塞 channel.configureBlocking(false); // 將channel 注冊(cè)到selector channel.register(selector, SelectionKey.OP_READ); name = channel.getLocalAddress().toString().substring(1); System.out.println(name + "is ok ...."); } // 向服務(wù)器發(fā)送消息 public void sendTO(String msg) { ByteBuffer buffer = ByteBuffer.wrap((name+":"+msg).getBytes()); try { channel.write(buffer); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // 讀取從服務(wù)器端回復(fù)的消息 public static void getInfo() { try { if(selector.select() >0) { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while(iterator.hasNext()) { SelectionKey key = iterator.next(); if(key.isReadable()) { // 得到通道 SocketChannel sc = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int len; // 把讀到的緩沖區(qū)的數(shù)據(jù)轉(zhuǎn)成字符串 while((len = sc.read(buffer)) > 0) { System.out.println(new String(buffer.array())); } } } // 刪除當(dāng)前的selectionKey, 防止重復(fù)操作 iterator.remove(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { try { GroupChatClient client = new GroupChatClient(); new Thread() { public void run() { while(true) { try { Thread.sleep(3000); GroupChatClient.getInfo(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start(); Scanner sc = new Scanner(System.in); // while(true) { // String name = sc.nextLine(); // client.sendTO(name); // } while(sc.hasNextLine()) { String s = sc.nextLine(); client.sendTO(s); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
Server端
package com.qst.chat; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.time.chrono.IsoChronology; import java.util.Iterator; import com.sun.accessibility.internal.resources.accessibility; import sun.print.resources.serviceui; public class GroupChatServer { private static ServerSocketChannel socketChannel; private static Socket socket; private static Selector selector; private static SocketChannel accept; public GroupChatServer() throws IOException { socketChannel = ServerSocketChannel.open(); selector = Selector.open(); // 綁定端口 socketChannel.socket().bind(new InetSocketAddress(9999)); // 設(shè)置非阻塞模式 socketChannel.configureBlocking(false); // 將該通道 注冊(cè)到selector socketChannel.register(selector, SelectionKey.OP_ACCEPT); } // 監(jiān)聽(tīng) public static void listen() { System.out.println("監(jiān)聽(tīng)線程: " + Thread.currentThread().getName()); try { while (selector.select() > 0) { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); if (iterator.hasNext()) { // 遍歷得到selectionKey 集合 SelectionKey next = iterator.next(); if (next.isAcceptable()) { next.channel(); // socketChannel = (ServerSocketChannel) next.channel(); SocketChannel accept = socketChannel.accept(); accept.configureBlocking(false); accept.register(selector, SelectionKey.OP_READ); System.out.println(accept.getRemoteAddress()+" 上線 了。。。"); } if (next.isReadable()) { readDate(next); } // 移除當(dāng)前的next,防止重復(fù)處理 iterator.remove(); // System.out.println("未發(fā)現(xiàn)"); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // 讀取客戶端消息 public static void readDate(SelectionKey key) { try { accept = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int len = accept.read(buffer); if (len > 0) { buffer.flip(); String msg = new String(buffer.array()); System.out.println("user = " + msg); // 向其它的客戶端轉(zhuǎn)發(fā)消息(去掉自己) sendToAll(msg, accept); buffer.clear(); } } catch (IOException e) { // TODO Auto-generated catch block try { String msg = accept.getRemoteAddress().toString(); // 取消注冊(cè) key.cancel(); // 關(guān)閉通道 accept.close(); System.out.println(msg + "離線了"); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // e.printStackTrace(); } finally { // TODO: handle finally clause } } public static void sendToAll(String msg, SocketChannel ssc) { for (SelectionKey ss : selector.keys()) { // 通過(guò) key 取出對(duì)應(yīng)的 SocketChannel SelectableChannel channel = ss.channel(); // 排除自己 if (channel instanceof SocketChannel && channel != ssc) { // 轉(zhuǎn)型 SocketChannel sh = (SocketChannel) channel; // 轉(zhuǎn)存到buffer ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes()); try { // 寫(xiě)入通道 sh.write(wrap); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) throws IOException { GroupChatServer server = new GroupChatServer(); GroupChatServer.listen(); } }
key.isAcceptable()進(jìn)行接入 操作的時(shí)候, 獲取通道有兩種方式
1、 通過(guò)selector獲取 (Selector key) socketChannel = (ServerSocketChannel) key.channel();
建立連接 socketChannel .accept();
2、定義一個(gè)全局變量
在進(jìn)行初始化的時(shí)候,存儲(chǔ)(socketChannel = ServerSocketChannel.open();)
建立連接 socketChannel .accept();
key.isReadable() 當(dāng)進(jìn)行到讀入操作的時(shí)候( ) SelectionKey key accept = (SocketChannel) key.channel();
服務(wù)器啟動(dòng),客戶端啟動(dòng)
客戶端發(fā)送消息
啟動(dòng)第二個(gè)客戶端
兩個(gè)客戶端相互通信
離線信息顯示
關(guān)于“java基于NIO如何實(shí)現(xiàn)群聊模式”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。