1. 程式人生 > >java nio--采用Selector實現Socket通信

java nio--采用Selector實現Socket通信

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 static
ByteBuffer 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通信