暫未考慮花大時間去學這些底層代碼,直接進入框架的學習,代碼來自網絡
Server
package spring.server; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Iterator; public class Server { /* * 處理器類 */ static class Handler { private int bufferSize = 1024; // 緩沖器容量 private String localCharset = "UTF-8"; // 編碼格式 public Handler() { } public Handler(int bufferSize) { this(bufferSize, null); } public Handler(String localCharset) { this(-1, localCharset); } public Handler(int bufferSize, String localCharset) { if (bufferSize > 0) { this.bufferSize = bufferSize; } if (localCharset != null) { this.localCharset = localCharset; } } /* * 連接請求處理方法 */ public void handleAccept(SelectionKey selectionKey) throws IOException { // 通過選擇器鍵獲取服務器套接字通道,通過accept()方法獲取套接字通道連接 SocketChannel socketChannel = ((ServerSocketChannel) selectionKey.channel()).accept(); // 設置套接字通道為非阻塞模式 socketChannel.configureBlocking(false); // 為套接字通道注冊選擇器,該選擇器為服務器套接字通道的選擇器,即選擇到該SocketChannel的選擇器 // 設置選擇器關心請求為讀操作,設置數據讀取的緩沖器容量為處理器初始化時候的緩沖器容量 socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize)); } public void handleRead(SelectionKey selectionKey) throws IOException { // 獲取套接字通道 SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); // 獲取緩沖器並進行重置,selectionKey.attachment()為獲取選擇器鍵的附加對象 ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment(); byteBuffer.clear(); // 沒有內容則關閉通道 if (socketChannel.read(byteBuffer) == -1) { socketChannel.close(); } else { // 將緩沖器轉換為讀狀態 byteBuffer.flip(); // 將緩沖器中接收到的值按localCharset格式編碼保存 String receivedRequestData = Charset.forName(localCharset).newDecoder().decode(byteBuffer).toString(); System.out.println("接收到客戶端的請求數據:" + receivedRequestData); // 返回響應數據給客戶端 String responseData = "已接收到你的請求數據,響應數據為:(響應數據)"; byteBuffer = ByteBuffer.wrap(responseData.getBytes(localCharset)); socketChannel.write(byteBuffer); // 關閉通道 socketChannel.close(); } } } public static void main(String[] args) { try { // 創建ServerSocketChannel通道,綁定監聽端口為8080 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(8080)); // 設置為非阻塞模式 serverSocketChannel.configureBlocking(false); // 注冊選擇器,設置選擇器選擇的操作類型 Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // 創建處理器 Handler handler = new Handler(1204); while (true) { // 等待請求,每次等待阻塞3s,超過時間則向下執行,若傳入0或不傳值,則在接收到請求前一直阻塞 if (selector.select(3000) == 0) { System.out.println("等待請求超時......"); continue; } System.out.println("-----處理請求-----"); // 獲取待處理的選擇鍵集合 Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator(); while (keyIterator.hasNext()) { SelectionKey selectionKey = keyIterator.next(); try { // 如果是連接請求,調用處理器的連接處理方法 if (selectionKey.isAcceptable()) { handler.handleAccept(selectionKey); } // 如果是讀請求,調用對應的讀方法 if (selectionKey.isReadable()) { handler.handleRead(selectionKey); } } catch (IOException e) { keyIterator.remove(); continue; } } // 處理完畢從待處理集合移除該選擇鍵 keyIterator.remove(); } } catch (IOException e) { e.printStackTrace(); } } }
Client
package spring.server; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class Client { public static void main(String[] args) throws IOException { SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080)); String newData = "New String to write to file..." + System.currentTimeMillis(); ByteBuffer buf = ByteBuffer.allocate(48); buf.clear(); buf.put(newData.getBytes()); buf.flip(); while (buf.hasRemaining()) { socketChannel.write(buf); } // socketChannel.configureBlocking(false); // socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80)); // // while(! socketChannel.finishConnect() ){ // //wait, or do something else... // } socketChannel.close(); } }