Java NIO(6):Server和Client案例
阿新 • • 發佈:2019-02-07
Server:
package com.tony.app; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; 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.util.Iterator; import java.util.Set; /** * 伺服器 * * @author TONY * */ public class Server { // 緩衝區的大小 private final static int BUFFER_SIZE = 1024; // 緩衝區 private ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); // Server監聽的埠號 // private final static int PORT = 8888; // 選擇器 private Selector selector = null; // 初始化工作 public void init(int port) throws IOException { System.out.println("============ Listening On Port : " + port + "============"); // 開啟伺服器套接字通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 設定為非阻塞狀態 serverSocketChannel.configureBlocking(false); // 獲取通道相關聯的套接字 ServerSocket serverSocket = serverSocketChannel.socket(); // 繫結埠號 serverSocket.bind(new InetSocketAddress(port)); // 開啟一個選擇器 selector = Selector.open(); // 伺服器套接字註冊到Selector中 並指定Selector監控連線事件 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } public void listen() throws IOException { while (true) { // 開啟選擇 int readyChannels = selector.select(); // 沒有通道就緒 一直阻塞 返回已經就緒通道的數目(有可能為0) if (readyChannels == 0) { continue; } // 返回已選擇鍵的集合 Set<SelectionKey> selectedKeys = selector.selectedKeys(); // 遍歷鍵 並檢查鍵對應的通道里註冊的就緒事件 Iterator iterator = selectedKeys.iterator(); while (iterator.hasNext()) { // SelectionKey封裝了一個通道和選擇器的註冊關係 SelectionKey key = (SelectionKey) iterator.next(); handleKey(key); // Selector不會移除SelectionKey 處理完了手動移除 iterator.remove(); } } } // 處理SelectionKey private void handleKey(SelectionKey key) throws IOException { // 是否有連線進來 if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key.channel();// 獲取通道 轉化為要處理的型別 SocketChannel socketChannel = server.accept(); // SocketChannel通道的可讀事件註冊到Selector中 registerChannel(selector, socketChannel, SelectionKey.OP_READ); // 連線成功 向Client打個招呼 if (socketChannel.isConnected()) { buffer.clear(); buffer.put("I am Server...".getBytes()); buffer.flip(); socketChannel.write(buffer); } } // 通道的可讀事件就緒 if (key.isReadable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); buffer.clear(); // 清空緩衝區 // 讀取資料 int len = 0; while ((len = socketChannel.read(buffer)) > 0) { buffer.flip(); while (buffer.hasRemaining()) { System.out.println("Server讀取的資料:" + new String(buffer.array(), 0, len)); } } if (len < 0) { // 非法的SelectionKey 關閉Channel socketChannel.close(); } // SocketChannel通道的可寫事件註冊到Selector中 registerChannel(selector, socketChannel, SelectionKey.OP_WRITE); } // 通道的可寫事件就緒 if (key.isWritable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); buffer.clear(); // 清空緩衝區 // 準備傳送的資料 String message_from_server = "Hello,Client... " + socketChannel.getLocalAddress(); buffer.put(message_from_server.getBytes()); buffer.flip(); socketChannel.write(buffer); System.out.println("Server傳送的資料:" + message_from_server); // SocketChannel通道的可寫事件註冊到Selector中 registerChannel(selector, socketChannel, SelectionKey.OP_READ); } } // 註冊通道到指定Selector上 private void registerChannel(Selector selector, SelectableChannel channel, int ops) throws IOException { if (channel == null) { return; } channel.configureBlocking(false); // 註冊通道 channel.register(selector, ops); } public static void main(String[] args) throws IOException { Server server = new Server(); server.init(8888); server.listen(); } }
Client:
package com.tony.app; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; /** * 客戶端 * * @author TONY * */ public class Client { // 緩衝區的大小 private final static int BUFFER_SIZE = 1024; // 緩衝區 private ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); // 選擇器 private Selector selector = null; private final static int PORT = 8888; // 初始化工作 public void init(String address) throws IOException { // 開啟客戶端套接字通道 SocketChannel socketChannel = SocketChannel.open(); // 設定為非阻塞狀態 socketChannel.configureBlocking(false); // 開啟選擇器 selector = Selector.open(); // 註冊 socketChannel.register(selector, SelectionKey.OP_CONNECT); // 發起連線 socketChannel.connect(new InetSocketAddress(address, PORT)); } public void connect() throws IOException { while (true) { int readyChannels = selector.select(); if (readyChannels == 0) { continue; } // 返回已選擇鍵的集合 Set<SelectionKey> selectedKeys = selector.selectedKeys(); // 遍歷鍵 並檢查鍵對應的通道里註冊的就緒事件 Iterator iterator = selectedKeys.iterator(); while (iterator.hasNext()) { // SelectionKey封裝了一個通道和選擇器的註冊關係 SelectionKey key = (SelectionKey) iterator.next(); handleKey(key); // Selector不會移除SelectionKey 處理完了手動移除 iterator.remove(); } } } // 處理SelectionKey private void handleKey(SelectionKey key) throws IOException { // 是否可連線 if (key.isConnectable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); // 完成連線 if(socketChannel.isConnectionPending()) { socketChannel.finishConnect(); System.out.println("連線成功..."); // 傳送資料給Server String message_to_server = "Hello,Server..."; buffer.clear(); buffer.put(message_to_server.getBytes()); buffer.flip(); socketChannel.write(buffer); System.out.println("Client傳送的資料:" + message_to_server); registerChannel(selector, socketChannel, SelectionKey.OP_READ); }else { System.exit(1); // 連線失敗 退出 } } // 通道的可讀事件就緒 if (key.isReadable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); buffer.clear(); // 清空緩衝區 // 讀取資料 int len = 0; while ((len = socketChannel.read(buffer)) > 0) { buffer.flip(); while (buffer.hasRemaining()) { System.out.println("Client讀取的資料:" + new String(buffer.array(), 0, len)); } } if (len < 0) { // 非法的SelectionKey 關閉Channel socketChannel.close(); } // SocketChannel通道的可寫事件註冊到Selector中 registerChannel(selector, socketChannel, SelectionKey.OP_WRITE); } // 通道的可寫事件就緒 if (key.isWritable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); buffer.clear(); // 清空緩衝區 // 準備傳送的資料 String message_from_server = "Hello,Server... " + socketChannel.getLocalAddress(); buffer.put(message_from_server.getBytes()); buffer.flip(); socketChannel.write(buffer); System.out.println("Client傳送的資料:" + message_from_server); // SocketChannel通道的可寫事件註冊到Selector中 registerChannel(selector, socketChannel, SelectionKey.OP_READ); } } // 註冊通道到指定Selector上 private void registerChannel(Selector selector, SelectableChannel channel, int ops) throws IOException { if (channel == null) { return; } channel.configureBlocking(false); // 註冊通道 channel.register(selector, ops); } public static void main(String[] args) throws IOException { Client client = new Client(); client.init("localhost"); client.connect(); } }