java nio--采用Selector實現Socket通信
阿新 • • 發佈:2017-06-19
lock finish taf 取數 block static isempty inpu col
server:
1 /** 2 * 選擇器服務端 3 * Created by ascend on 2017/6/9 9:30. 4 */ 5 public class SelectorServer { 6 // public final static String REMOTE_IP = "192.168.0.44"; 7 public final static String REMOTE_IP = "127.0.0.1"; 8 public final static int PORT = 17531; 9 private staticByteBuffer bb = ByteBuffer.allocate(1024); 10 private static ServerSocketChannel ssc; 11 private static boolean closed = false; 12 13 public static void main(String[] args) throws IOException { 14 //先確定端口號 15 int port = PORT; 16 if (args != null && args.length > 0) {17 port = Integer.parseInt(args[0]); 18 } 19 //打開一個ServerSocketChannel 20 ssc = ServerSocketChannel.open(); 21 //獲取ServerSocketChannel綁定的Socket 22 ServerSocket ss = ssc.socket(); 23 //設置ServerSocket監聽的端口 24 ss.bind(new InetSocketAddress(port));25 //設置ServerSocketChannel為非阻塞模式 26 ssc.configureBlocking(false); 27 //打開一個選擇器 28 Selector selector = Selector.open(); 29 //將ServerSocketChannel註冊到選擇器上去並監聽accept事件 30 SelectionKey selectionKey = ssc.register(selector, SelectionKey.OP_ACCEPT); 31 32 33 while (!closed) { 34 //這裏會發生阻塞,等待就緒的通道,但在每次select()方法調用之間,只有一個通道就緒了。 35 int n = selector.select(); 36 //沒有就緒的通道則什麽也不做 37 if (n == 0) { 38 continue; 39 } 40 //獲取SelectionKeys上已經就緒的集合 41 Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); 42 43 //遍歷每一個Key 44 while (iterator.hasNext()) { 45 SelectionKey sk = iterator.next(); 46 //通道上是否有可接受的連接 47 if (sk.isAcceptable()) { 48 ServerSocketChannel sscTmp = (ServerSocketChannel) sk.channel(); 49 SocketChannel sc = sscTmp.accept(); // accept()方法會一直阻塞到有新連接到達。 50 sc.configureBlocking(false); 51 sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); 52 } else if (sk.isReadable()) { //通道上是否有數據可讀 53 try { 54 readDataFromSocket(sk); 55 } catch (IOException e) { 56 sk.cancel(); 57 continue; 58 } 59 } 60 if (sk.isWritable()) { //測試寫入數據,若寫入失敗在會自動取消註冊該鍵 61 try { 62 writeDataToSocket(sk); 63 } catch (IOException e) { 64 sk.cancel(); 65 continue; 66 } 67 } 68 //必須在處理完通道時自己移除。下次該通道變成就緒時,Selector會再次將其放入已選擇鍵集中。 69 iterator.remove(); 70 }//. end of while 71 72 } 73 74 } 75 76 77 78 /** 79 * 發送測試數據包,若失敗則認為該socket失效 80 * 81 * @param sk SelectionKey 82 * @throws IOException IOException 83 */ 84 private static void writeDataToSocket(SelectionKey sk) throws IOException { 85 SocketChannel sc = (SocketChannel) sk.channel(); 86 bb.clear(); 87 String str = "server data"; 88 bb.put(str.getBytes()); 89 while (bb.hasRemaining()) { 90 sc.write(bb); 91 } 92 } 93 94 /** 95 * 從通道中讀取數據 96 * 97 * @param sk SelectionKey 98 * @throws IOException IOException 99 */ 100 private static void readDataFromSocket(SelectionKey sk) throws IOException { 101 SocketChannel sc = (SocketChannel) sk.channel(); 102 bb.clear(); 103 List<Byte> list = new ArrayList<>(); 104 while (sc.read(bb) > 0) { 105 bb.flip(); 106 while (bb.hasRemaining()) { 107 list.add(bb.get()); 108 } 109 bb.clear(); 110 } 111 byte[] bytes = new byte[list.size()]; 112 for (int i = 0; i < bytes.length; i++) { 113 bytes[i] = list.get(i); 114 } 115 String s = (new String(bytes)).trim(); 116 if (!s.isEmpty()) { 117 if ("exit".equals(s)){ 118 ssc.close(); 119 closed = true; 120 } 121 System.out.println("服務器收到:" + s); 122 } 123 } 124 125 }
client:
1 /** 2 * 3 * Created by ascend on 2017/6/13 10:36. 4 */ 5 public class Client { 6 7 @org.junit.Test 8 public void test(){ 9 Socket socket = new Socket(); 10 try { 11 socket.connect(new InetSocketAddress(SelectorServer.REMOTE_IP,SelectorServer.PORT)); 12 DataOutputStream out = new DataOutputStream(socket.getOutputStream()); 13 out.write("exit".getBytes()); 14 out.flush(); 15 out.close(); 16 socket.close(); 17 } catch (IOException e) { 18 e.printStackTrace(); 19 } 20 } 21 22 public static void main(String[] args) { 23 new Thread(new ClientThread()).start(); 24 } 25 26 public void checkStatus(String input){ 27 if ("exit".equals(input.trim())) { 28 System.out.println("系統即將退出,bye~~"); 29 System.exit(0); 30 } 31 } 32 33 34 } 35 36 class ClientThread implements Runnable { 37 private SocketChannel sc; 38 private boolean isConnected = false; 39 Client client = new Client(); 40 41 public ClientThread(){ 42 try { 43 sc = SocketChannel.open(); 44 sc.configureBlocking(false); 45 sc.connect(new InetSocketAddress(SelectorServer.REMOTE_IP,SelectorServer.PORT)); 46 while (!sc.finishConnect()) { 47 System.out.println("同" + SelectorServer.REMOTE_IP + "的連接正在建立,請稍等!"); 48 Thread.sleep(10); 49 } 50 System.out.println("連接已建立,待寫入內容至指定ip+端口!時間為" + System.currentTimeMillis()); 51 } catch (IOException | InterruptedException e) { 52 e.printStackTrace(); 53 } 54 } 55 56 @Override 57 public void run() { 58 try { 59 while (true){ 60 Scanner scanner = new Scanner(System.in); 61 System.out.print("請輸入要發送的內容:"); 62 String writeStr = scanner.nextLine(); 63 client.checkStatus(writeStr); 64 ByteBuffer bb = ByteBuffer.allocate(writeStr.length()); 65 bb.put(writeStr.getBytes()); 66 bb.flip(); // 寫緩沖區的數據之前一定要先反轉(flip) 67 while (bb.hasRemaining()){ 68 sc.write(bb); 69 } 70 bb.clear(); 71 } 72 } catch (IOException e) { 73 e.printStackTrace(); 74 if (Objects.nonNull(sc)) { 75 try { 76 sc.close(); 77 } catch (IOException e1) { 78 e1.printStackTrace(); 79 } 80 } 81 }finally { 82 if (Objects.nonNull(sc)) { 83 try { 84 sc.close(); 85 } catch (IOException e1) { 86 e1.printStackTrace(); 87 } 88 } 89 } 90 } 91 }
java nio--采用Selector實現Socket通信