Java基于NIO實現(xiàn)群聊功能
更新時間:2021年11月23日 17:15:19 作者:大樹下躲雨
這篇文章主要為大家詳細介紹了Java基于NIO實現(xiàn)群聊功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
本文實例為大家分享了Java基于NIO實現(xiàn)群聊功能的具體代碼,供大家參考,具體內容如下
一、群聊服務器
package com.dashu.netty.group_chat; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.charset.StandardCharsets; import java.util.Iterator; public class GroupChatServer { /** * 初始化選擇器 */ private Selector selector; /** * 初始化服務器網(wǎng)絡通道 */ private ServerSocketChannel serverSocketChannel; /** * 端口 */ private static final int PORT = 6666; /** * 構造方法 */ public GroupChatServer() { try { //獲取選擇器 selector = Selector.open(); //獲取服務器網(wǎng)絡通道 serverSocketChannel = ServerSocketChannel.open(); //網(wǎng)絡地址 InetSocketAddress inetSocketAddress = new InetSocketAddress(PORT); //服務器網(wǎng)絡通道綁定網(wǎng)絡地址 serverSocketChannel.socket().bind(inetSocketAddress); //設置服務器網(wǎng)絡通道非阻塞 serverSocketChannel.configureBlocking(false); //將服務器網(wǎng)絡通道注冊到選擇器上,綁定連接請求事件 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (Exception e) { e.printStackTrace(); } } /** * 監(jiān)聽客戶端請求事件 */ public void listen() { try { //無限循環(huán) while (true) { //獲取請求數(shù) int count = selector.select(); //count大于0,則代表有請求進來 if (count > 0) { //獲取請求集 Iterator<SelectionKey> selectionKeyIterator = selector.selectedKeys().iterator(); //遍歷請求集 while (selectionKeyIterator.hasNext()) { //得到請求 SelectionKey selectionKey = selectionKeyIterator.next(); //連接請求 if (selectionKey.isAcceptable()) { //獲取客戶端網(wǎng)絡通道 SocketChannel socketChannel = serverSocketChannel.accept(); //設置客戶端網(wǎng)絡通道非阻塞 socketChannel.configureBlocking(false); //將客戶端網(wǎng)絡通道注冊到選擇器上 socketChannel.register(selector, SelectionKey.OP_READ); System.out.println(socketChannel.getRemoteAddress() + "上線了"); } //信息讀取請求 if (selectionKey.isReadable()) { //客戶端信息讀取 readData(selectionKey); } //移除請求 selectionKeyIterator.remove(); } } else { System.out.println("等待..."); } } } catch (Exception e) { e.printStackTrace(); } } /** * 客戶端信息讀取 * * @param selectionKey */ private void readData(SelectionKey selectionKey) { //初始化客戶端網(wǎng)絡通道 SocketChannel socketChannel = null; try { //獲取客戶端網(wǎng)絡通道 socketChannel = (SocketChannel) selectionKey.channel(); //創(chuàng)建緩沖區(qū) ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //讀取客戶端網(wǎng)絡通道中的數(shù)據(jù)到緩沖區(qū) int count = socketChannel.read(byteBuffer); //判斷緩沖區(qū)中是否有數(shù)據(jù) if (count > 0) { //將緩沖區(qū)的數(shù)據(jù)轉換位字符串 String message = new String(byteBuffer.array()); System.out.println(message.trim()); //將信息群發(fā)到其他客戶端 sendInfoToOtClients(message, socketChannel); } } catch (Exception e) { e.printStackTrace(); } } /** * 將信息群發(fā)到其他客戶端 * * @param message * @param socketChannel */ private void sendInfoToOtClients(String message, SocketChannel socketChannel) { //獲取所有注冊到選擇器的客戶端,并遍歷 for (SelectionKey selectionKey : selector.keys()) { //獲取通道 Channel channel = selectionKey.channel(); //判斷通道是否屬于SocketChannel,同時不等于發(fā)送信息的客戶端 if (channel instanceof SocketChannel && channel != socketChannel) { //通道轉換 SocketChannel sc = (SocketChannel) channel; //將信息寫入緩沖區(qū) ByteBuffer byteBuffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8)); try { //將緩沖區(qū)的數(shù)據(jù)寫入通道 sc.write(byteBuffer); } catch (Exception e) { e.printStackTrace(); } } } } public static void main(String[] args) { GroupChatServer groupChatServer = new GroupChatServer(); System.out.println("服務器啟動,開始監(jiān)聽客戶端請求..."); groupChatServer.listen(); } }
二、客戶端
package com.dashu.netty.group_chat; 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.nio.charset.StandardCharsets; import java.util.Iterator; import java.util.Scanner; public class GroupChatClient { /** * 網(wǎng)絡連接地址 */ private final String HOST = "127.0.0.1"; /** * 端口 */ private final int PORT = 6666; /** * 初始化選擇器 */ private Selector selector; /** * 初始化網(wǎng)絡通道 */ private SocketChannel socketChannel; /** * 用戶名 */ private String username; public GroupChatClient() { try { //獲取選擇器 selector = Selector.open(); //獲取服務器網(wǎng)絡地址 InetSocketAddress inetSocketAddress = new InetSocketAddress(HOST, PORT); //獲取網(wǎng)絡通道 socketChannel = SocketChannel.open(inetSocketAddress); //設置網(wǎng)絡通道非阻塞 socketChannel.configureBlocking(false); //將網(wǎng)絡通道注冊到選擇器 socketChannel.register(selector, SelectionKey.OP_READ); //獲取用戶名 System.out.println("請輸入用戶名:"); Scanner scanner = new Scanner(System.in); username = scanner.nextLine(); System.out.println(username + " 進入群聊..."); } catch (Exception e) { e.printStackTrace(); } } /** * 向服務器發(fā)送信息 * * @param message */ public void sendInfo(String message) { message = username + ":" + message; try { //向通道寫入數(shù)據(jù) socketChannel.write(ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8))); } catch (Exception e) { e.printStackTrace(); } } /** * 讀取服務器發(fā)來的信息 */ public void readInfo() { try { //獲取請求數(shù) int count = selector.select(); if (count > 0) { //獲取請求集 Iterator<SelectionKey> selectionKeyIterator = selector.selectedKeys().iterator(); //遍歷請求集 while (selectionKeyIterator.hasNext()) { //獲取請求 SelectionKey selectionKey = selectionKeyIterator.next(); //判斷位讀請求 if (selectionKey.isReadable()) { //獲取通道 SocketChannel sc = (SocketChannel) selectionKey.channel(); //創(chuàng)建緩沖區(qū) ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //讀取通道的數(shù)據(jù)到緩沖區(qū) sc.read(byteBuffer); //緩沖區(qū)數(shù)據(jù)轉字符串 String message = new String(byteBuffer.array()); //輸出 System.out.println(message.trim()); } //移除已完成請求 selectionKeyIterator.remove(); } } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { GroupChatClient groupChatClient = new GroupChatClient(); /** * 開啟一個線程,每3秒讀取一次服務器發(fā)來的信息 */ new Thread() { @Override public void run() { while (true) { groupChatClient.readInfo(); try { Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } } } }.start(); //信息輸入 Scanner scanner = new Scanner(System.in); System.out.println("請輸入信息:"); while (scanner.hasNextLine()) { String s = scanner.nextLine(); //信息發(fā)送 groupChatClient.sendInfo(s); System.out.println("請輸入信息:"); } } }
三、效果圖
1、服務器
2、客戶端01
3、客戶端02
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Java?restTemplate發(fā)送get請求query參數(shù)傳遞問題解決
這篇文章主要為大家介紹了Java?restTemplate發(fā)送get請求query參數(shù)傳遞問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11MyBatis?Puls統(tǒng)一封裝前端傳遞的分頁排序實例
這篇文章主要為大家介紹了MyBatis?Puls統(tǒng)一封裝前端傳遞的分頁排序實現(xiàn)實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12SpringMVC實現(xiàn)Validation校驗過程詳解
這篇文章主要介紹了SpringMVC實現(xiàn)Validation校驗過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11Springboot集成kafka高級應用實戰(zhàn)分享
這篇文章主要介紹了Springboot集成kafka高級應用實戰(zhàn)分享,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08