日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NIO网络编程实战之简单多人聊天室

發布時間:2025/4/16 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NIO网络编程实战之简单多人聊天室 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

NIO網絡編程實戰
利用NIO編程知識,實現多人聊天室。

1. NIO編程實現步驟

第一步:創建Selector

第二步:創建ServerSocketChannel,并綁定監聽端口

第三步:將Channel設置為非阻塞模式

第四步:將Channel注冊到Selector上,監聽連接事件

第五步:循環調用Selector的select方法,檢測就緒情況

第六步:調用selectedKeys方法獲取就緒channel集合

第七步:判斷就緒事件種類,調用業務處理方法

第八步:根據業務需要決定是否再次注冊監聽事件,重復執行第三步操作

2. NIO網絡編程實戰

利用NIO編程知識,實現多人聊天室。

2.1 程序結構目錄

2.2 服務器端程序

package com.xuxin.niochatroom;import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.charset.Charset; import java.util.Iterator; import java.util.Set;/*** NIO服務器端*/ public class NioServer {/*** 啟動*/public void start() throws IOException {// 1. 創建SelectorSelector selector = Selector.open();// 2. 通過ServerSocketChannel創建channel通道ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 3. 為channel通道綁定監聽端口serverSocketChannel.bind(new InetSocketAddress(8000));// 4. 設置channel為非阻塞模式serverSocketChannel.configureBlocking(false);// 5. 將channel注冊到selector上,監聽連接事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("服務器啟動成功!");// 6. 循環等待新接入的連接for (;;) {// 獲取可用channel的數量int readyChannels = selector.select();if (readyChannels == 0) {continue;}// 獲取可用channel的集合Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator iterator = selectionKeys.iterator();while(iterator.hasNext()) {// selectionKey實例SelectionKey selectionKey = (SelectionKey) iterator.next();// 移除Set中的當前selectionKeyiterator.remove();// 7. 根據就緒狀態,調用對應方法處理業務邏輯// 如果是 接入事件if (selectionKey.isAcceptable()) {acceptHandler(serverSocketChannel, selector);}// 如果是 可讀事件if (selectionKey.isReadable()) {readHandler(selectionKey, selector);}}}}/*** 接入事件處理器*/private void acceptHandler(ServerSocketChannel serverSocketChannel,Selector selector) throws IOException {// 如果要是接入事件,創建socketChannelSocketChannel socketChannel = serverSocketChannel.accept();// 將socketChannel設置為非阻塞工作模式socketChannel.configureBlocking(false);// 將channel注冊到selector上,監聽 可讀事件socketChannel.register(selector, SelectionKey.OP_READ);// 回復客戶端提示信息socketChannel.write(Charset.forName("UTF-8").encode("你與聊天室里其他人都不是朋友關系,請注意隱私安全"));}/*** 可讀事件處理器*/private void readHandler(SelectionKey selectionKey, Selector selector)throws IOException {// 要從selectionKey中獲取到已經就緒的channelSocketChannel socketChannel = (SocketChannel) selectionKey.channel();// 創建bufferByteBuffer byteBuffer = ByteBuffer.allocate(1024);// 循環讀取客戶端請求信息String request = "";while (socketChannel.read(byteBuffer) > 0) {// 切換buffer為讀模式byteBuffer.flip();// 讀取buffer中的內容request += Charset.forName("UTF-8").decode(byteBuffer);}// 將channel再次注冊到selector上,監聽他的可讀事件socketChannel.register(selector, selectionKey.OP_READ);// 將客戶端發送的請求信息 廣播給其他客戶端if (request.length() > 0) {// 廣播給其他客戶端broadCast(selector, socketChannel, request);}}/*** 廣播給其他客戶端*/private void broadCast(Selector selector, SocketChannel sourceChannel, String request) {// 獲取到所有已接入的客戶端channelSet<SelectionKey> selectionKeySet = selector.keys();// 循環向所有channel廣播信息selectionKeySet.forEach(selectionKey -> {Channel targetChannel = selectionKey.channel();// 剔除發消息的客戶端if ((targetChannel instanceof SocketChannel) && (targetChannel != sourceChannel)) {try {// 將信息群發給target的客戶端((SocketChannel) targetChannel).write(Charset.forName("UTF-8").encode(request));} catch (IOException e) {e.printStackTrace();}}});}/*** 主程序* @param args*/public static void main(String[] args) throws IOException {NioServer nioServer = new NioServer();nioServer.start();} }

2.3 客戶端程序

package com.xuxin.niochatroom;import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Scanner;/*** NIO客戶端*/ public class NioClient {/*** 啟動*/public void start(String nickName) throws IOException {// 連接服務器SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8000));// 接收服務器端響應// 創建線程,專門負責接收服務器端的響應數據// selector socketChannel 注冊Selector selector = Selector.open();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);new Thread(new NioClientHandler(selector)).start();// 向服務器端發送數據Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()) {String request = scanner.nextLine();if ((request != null) && (request.length() > 0)) {socketChannel.write(Charset.forName("UTF-8").encode(nickName + " : " + request));}}} }

2.4 客戶端處理服務器端響應的線程

package com.xuxin.niochatroom;import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Iterator; import java.util.Set;public class NioClientHandler implements Runnable {private Selector selector;public NioClientHandler(Selector selector) {this.selector = selector;}@Overridepublic void run() {try {// 1. 循環等待服務器端響應for (; ; ) {// 獲取可用channel的數量int readyChannels = selector.select();if (readyChannels == 0) {continue;}// 獲取可用channel的集合Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator iterator = selectionKeys.iterator();while (iterator.hasNext()) {// selectionKey實例SelectionKey selectionKey = (SelectionKey) iterator.next();// 移除Set中的當前selectionKeyiterator.remove();// 7. 根據就緒狀態,調用對應方法處理業務邏輯// 如果是 可讀事件if (selectionKey.isReadable()) {readHandler(selectionKey, selector);}}}} catch (IOException e) {e.printStackTrace();}}/*** 可讀事件處理器*/private void readHandler(SelectionKey selectionKey, Selector selector)throws IOException {// 要從selectionKey中獲取到已經就緒的channelSocketChannel socketChannel = (SocketChannel) selectionKey.channel();// 創建bufferByteBuffer byteBuffer = ByteBuffer.allocate(1024);// 循環讀取服務器端的響應數據String reponse = "";while (socketChannel.read(byteBuffer) > 0) {// 切換buffer為讀模式byteBuffer.flip();// 讀取buffer中的內容reponse += Charset.forName("UTF-8").decode(byteBuffer);}// 將channel再次注冊到selector上,監聽他的可讀事件socketChannel.register(selector, selectionKey.OP_READ);// 將服務器端的響應數據打印到本地if (reponse.length() > 0) {System.out.println(":: " + reponse);}} }

2.5 測試

2.5.1 創建用于測試的客戶端類

ClientA:

package com.xuxin.niochatroom;import java.io.IOException;public class ClientA {public static void main(String[] args) throws IOException {new NioClient().start("ClientA");} }

ClientB:

package com.xuxin.niochatroom;import java.io.IOException;public class ClientB {public static void main(String[] args) throws IOException {new NioClient().start("ClientB");} }

ClientC:

package com.xuxin.niochatroom;import java.io.IOException;public class ClientC {public static void main(String[] args) throws IOException {new NioClient().start("ClientC");} }

2.5.2 結果

啟動服務器端

啟動ClientA、ClientB、ClientC,并先由ClientA開始輸入聊天信息,再由ClientB開始輸入聊天信息,最后由ClientC開始輸入聊天信息

2.6 NIO網絡編程缺陷

麻煩

NIO類庫和API繁雜。需要了解ServerSocketChannel、SocketChannel、ByteBuffer等核心類庫的使用

問題

可靠性能力補齊,工作量和難度都非常大。
客戶端的斷連、重連、網絡閃斷、失敗緩存、網絡阻塞和異常碼流等問題。

有坑

Selector空輪詢,導致CPU100%。

總結

以上是生活随笔為你收集整理的NIO网络编程实战之简单多人聊天室的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。