Java?NIO實現(xiàn)聊天系統(tǒng)
更新時間:2021年11月24日 12:11:49 作者:菜鳥程序猿進階之路
這篇文章主要為大家詳細介紹了Java?NIO實現(xiàn)聊天系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
使用Java的NIO寫的一個小的聊天系統(tǒng),供大家參考,具體內容如下
一、服務端
/** * 群聊的服端 * * @author :breakpoint/趙立剛 * @date : 2020/08/13 */ public class GroupChatServer { // 定義相關的屬性 private Selector selector; private ServerSocketChannel listenChannel; private static final int port = 6667; // 構造器 // 進行初始化的操作 public GroupChatServer() { try { // 獲取選擇器 selector = Selector.open(); // 獲取到 listenChannel listenChannel = ServerSocketChannel.open(); // 設定端口 listenChannel.bind(new InetSocketAddress(port)); // 設定非阻塞模式 listenChannel.configureBlocking(false); // 將該 listenChannel 注冊到 selector上 完成操作 listenChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("服務器啟動了。。。。"); } catch (IOException e) { } } // 監(jiān)聽的代碼 public void listen() { try { // 循環(huán)處理 while (true) { int count = selector.select(2000); if (count > 0) { // 有事件需要處理 // 遍歷處理 得到selectionKeys集合 Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator(); while (selectionKeyIterator.hasNext()) { // 得到selectionKey SelectionKey selectionKey = selectionKeyIterator.next(); // 監(jiān)聽到了 accept if (selectionKey.isAcceptable()) { // 獲取到連接 SocketChannel sc = listenChannel.accept(); sc.configureBlocking(false); sc.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024)); // 提示上線 System.out.println(sc.getRemoteAddress() + ":上線啦。。。。"); } if (selectionKey.isReadable()) { // 讀取事件 通道是可以讀的狀態(tài) //專門寫 readData(selectionKey); } // 移除當前的刪除 防止重復處理操作 selectionKeyIterator.remove(); } } else { System.out.println("等待中。。。。。。"); } } } catch (Exception e) { } finally { } } // 讀取客戶端的消息 private void readData(SelectionKey selectionKey) { // 獲取 socketChannel SocketChannel channel = null; try { channel = (SocketChannel) selectionKey.channel(); ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment(); int count = channel.read(byteBuffer); // 分情況處理 if (count > 0) { // 獲取到數(shù)據(jù)專程 String msg = new String(byteBuffer.array(), 0, count); byteBuffer.clear(); System.out.println(channel.getRemoteAddress() + "來自客戶端" + msg); // 向其他的客戶端轉發(fā)消息 sendInfoToOtherClients(msg, channel); } } catch (IOException e) { // 如果發(fā)生異常 提示說明離線了 try { System.out.println(channel.getRemoteAddress() + "離線了。。。。"); // 取消注冊 selectionKey.cancel(); // 關閉通道 channel.close(); } catch (IOException e1) { //e1.printStackTrace(); } } finally { } } // 轉發(fā)消息給其他的客戶端 去掉自己的客戶端 private void sendInfoToOtherClients(String msg, SocketChannel self) throws IOException { System.out.println("服務器轉發(fā)消息。。。。。"); // 進行遍歷操作 Set<SelectionKey> keys = selector.keys(); for (SelectionKey key : keys) { // 取出來所有的 Channel targetChannel = key.channel(); // 排除自己 if (targetChannel instanceof SocketChannel && targetChannel != self) { SocketChannel dest = (SocketChannel) targetChannel; ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes()); // 發(fā)送數(shù)據(jù) dest.write(byteBuffer); } } } public static void main(String[] args) { GroupChatServer groupChatServer = new GroupChatServer(); groupChatServer.listen(); } }
二、客戶端代碼
/** * @author :breakpoint/趙立剛 * @date : 2020/08/13 */ public class GroupChatClient { // 定義相關屬性 private final String HOST = "127.0.0.1"; //服務器地址 private final int port = 6667; // 服務器端口 private Selector selector; private SocketChannel socketChannel; private String userName; // 完成初始化工作 public GroupChatClient() { try { selector = Selector.open(); // 連接服務器 socketChannel = SocketChannel.open(new InetSocketAddress(HOST, port)); // 設置非阻塞工作 socketChannel.configureBlocking(false); // 注冊我們的通道 socketChannel.register(selector, SelectionKey.OP_READ); userName = socketChannel.getLocalAddress().toString(); System.out.println("客戶端專備好啦"); } catch (IOException e) { } } public void sendInfo(String info) { String msg = userName + "說:" + info; try { ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes()); socketChannel.write(wrap); } catch (IOException e) { e.printStackTrace(); } } // 讀取信息 public void readInfo() { try { int readChannel = selector.select(2000); if (readChannel > 0) { // 有可以用的通道 Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); while (iterator.hasNext()) { SelectionKey next = iterator.next(); if (next.isReadable()) { SelectableChannel keyChannel = next.channel(); if (keyChannel instanceof SocketChannel) { // 獲取到我們的通道 SocketChannel channel = (SocketChannel) keyChannel; ByteBuffer allocate = ByteBuffer.allocate(1024); // 讀取數(shù)據(jù) int read = channel.read(allocate); if (read > 0) { // 輸出我們的消息 System.out.println(new String(allocate.array(), 0, read)); } }// end if } iterator.remove(); } } else { System.out.println("沒有可用的通道"); } } catch (IOException e) { } } public static void main(String[] args) throws Exception { // 啟動客戶端的操作 final GroupChatClient groupChatClient = new GroupChatClient(); // 啟動一個線程 new Thread(() -> { while (true) { groupChatClient.readInfo(); try { Thread.currentThread().sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { // 輸入信息 String s = scanner.nextLine(); groupChatClient.sendInfo(s); } System.in.read(); } }
三、運行的結果
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。?
相關文章
java開發(fā)MVC三層架構上再加一層Manager層原理詳解
這篇文章主要為大家介紹了MVC三層架構中再加一層Manager層原理的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2021-10-10Java中static修飾的靜態(tài)變量、方法及代碼塊的特性與使用
這篇文章主要介紹了Java中static修飾的靜態(tài)變量、方法及代碼塊的特性與使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-04-04基于JAVA中Jersey處理Http協(xié)議中的Multipart的詳解
之前在基于C#開發(fā)彩信用最原始的StringBuilder拼接字符串方式處理過Multipart?,F(xiàn)在在做一個項目的時候,由于之前的技術路線都是使用Jersey處理Http這塊,為了保持技術路線一致,研究了一下如何使用Jersey處理Http協(xié)議中的Multipart2013-05-05