NIO多人聊天客戶端
阿新 • • 發佈:2022-03-05
多人聊天客戶端
服務端
public class Server { private ServerSocketChannel servSocketChannel; private Selector selector; /** * 初始化伺服器 * */ public Server(){ try { servSocketChannel = ServerSocketChannel.open(); servSocketChannel.socket().bind(new InetSocketAddress(7000)); selector = Selector.open(); //開啟非阻塞模式 servSocketChannel.configureBlocking(false); //註冊serverSocketChannel servSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (IOException e) { e.printStackTrace(); } } /** * 監聽連線 * */ public void listen() { while (true) { Iterator<SelectionKey> keyIterator = null; try { //這裡我們等待1秒,如果沒有事件發生, 返回 if(selector.select(1000) == 0) { //沒有事件發生 continue; } Set<SelectionKey> selectionKeys = selector.selectedKeys(); keyIterator = selectionKeys.iterator(); if(keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); //客戶端連線 if(key.isAcceptable()) { SocketChannel socketChannel = servSocketChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); System.out.println(socketChannel.getRemoteAddress() + "上線"); } //讀已就緒 if(key.isReadable()) { readData(key); }else{ System.out.println("等待處理"); } } } catch (Exception e) { e.printStackTrace(); } //當前的key 刪除,防止重複處理 keyIterator.remove(); } } public void readData(SelectionKey selectionKey) { SocketChannel channel = (SocketChannel)selectionKey.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); try { int read = channel.read(byteBuffer); while (read > 0) { String msg = new String(byteBuffer.array()); System.out.println(msg); //轉發 sendInfoToOtherClients(msg, channel); byteBuffer.clear(); read = channel.read(byteBuffer); } } catch (Exception e) { e.printStackTrace(); selectionKey.cancel(); } } private void sendInfoToOtherClients(String msg, SocketChannel channel) { Set<SelectionKey> keys = selector.keys(); for (SelectionKey key : keys) { SelectableChannel targetChannel = key.channel(); if(targetChannel instanceof SocketChannel && targetChannel != channel) { SocketChannel socketChannel = (SocketChannel) targetChannel; ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes()); try { socketChannel.write(wrap); } catch (IOException e) { e.printStackTrace(); } } } } public static void main(String[] args) { Server server = new Server(); server.listen(); } }
客戶端
public class Client { private SocketChannel socketChannel; private final String IP = "127.0.0.1"; private Selector selector; private final int port = 7000; private String username; public Client() { try { socketChannel = SocketChannel.open(new InetSocketAddress(IP, port)); selector = Selector.open(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); username = socketChannel.getLocalAddress().toString().substring(1); System.out.println(username + " is ok..."); } catch (IOException e) { e.printStackTrace(); } } //讀取從伺服器端回覆的訊息 public void readInfo() { try { int readChannels = selector.select(); if(readChannels > 0) {//有可以用的通道 Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); if(key.isReadable()) { //得到相關的通道 SocketChannel sc = (SocketChannel) key.channel(); //得到一個Buffer ByteBuffer buffer = ByteBuffer.allocate(1024); //讀取 sc.read(buffer); //把讀到的緩衝區的資料轉成字串 String msg = new String(buffer.array()); System.out.println(msg.trim()); } } iterator.remove(); //刪除當前的selectionKey, 防止重複操作 } else { //System.out.println("沒有可以用的通道..."); } }catch (Exception e) { e.printStackTrace(); } } //向伺服器傳送訊息 public void sendInfo(String info) { info = username + " 說:" + info; try { socketChannel.write(ByteBuffer.wrap(info.getBytes())); }catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { //啟動我們客戶端 Client chatClient = new Client(); //啟動一個執行緒, 每個3秒,讀取從伺服器傳送資料 new Thread() { public void run() { while (true) { chatClient.readInfo(); try { Thread.currentThread().sleep(3000); }catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); //傳送資料給伺服器端 Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()) { String s = scanner.nextLine(); chatClient.sendInfo(s); } } }