1. 程式人生 > >java NIO服務端和客戶端程式碼實現

java NIO服務端和客戶端程式碼實現

  1. package cn.nio; 
  2. import java.io.IOException; 
  3. import java.net.InetSocketAddress; 
  4. import java.nio.ByteBuffer; 
  5. import java.nio.channels.SelectionKey; 
  6. import java.nio.channels.Selector; 
  7. import java.nio.channels.ServerSocketChannel; 
  8. import java.nio.channels.SocketChannel; 
  9. import java.util.Iterator; 
  10. /**
  11. * NIO服務端
  12. * @author 小路
  13. */
  14. public class NIOServer { 
  15. //通道管理器
  16. private Selector selector; 
  17. /**
  18.      * 獲得一個ServerSocket通道,並對該通道做一些初始化的工作
  19.      * @param port  繫結的埠號
  20.      * @throws IOException
  21.      */
  22. public void initServer(int port) throws IOException { 
  23. // 獲得一個ServerSocket通道
  24.         ServerSocketChannel serverChannel = ServerSocketChannel.open(); 
  25. // 設定通道為非阻塞
  26.         serverChannel.configureBlocking(false); 
  27. // 將該通道對應的ServerSocket繫結到port埠
  28.         serverChannel.socket().bind(new InetSocketAddress(port)); 
  29. // 獲得一個通道管理器
  30. this.selector = Selector.open(); 
  31. //將通道管理器和該通道繫結,併為該通道註冊SelectionKey.OP_ACCEPT事件,註冊該事件後,
  32. //當該事件到達時,selector.select()會返回,如果該事件沒到達selector.select()會一直阻塞。
  33.         serverChannel.register(selector, SelectionKey.OP_ACCEPT); 
  34.     } 
  35. /**
  36.      * 採用輪詢的方式監聽selector上是否有需要處理的事件,如果有,則進行處理
  37.      * @throws IOException
  38.      */
  39. @SuppressWarnings("unchecked") 
  40. public void listen() throws IOException { 
  41.         System.out.println("服務端啟動成功!"); 
  42. // 輪詢訪問selector
  43. while (true) { 
  44. //當註冊的事件到達時,方法返回;否則,該方法會一直阻塞
  45.             selector.select(); 
  46. // 獲得selector中選中的項的迭代器,選中的項為註冊的事件
  47.             Iterator ite = this.selector.selectedKeys().iterator(); 
  48. while (ite.hasNext()) { 
  49.                 SelectionKey key = (SelectionKey) ite.next(); 
  50. // 刪除已選的key,以防重複處理
  51.                 ite.remove(); 
  52. // 客戶端請求連線事件
  53. if (key.isAcceptable()) { 
  54.                     ServerSocketChannel server = (ServerSocketChannel) key 
  55.                             .channel(); 
  56. // 獲得和客戶端連線的通道
  57.                     SocketChannel channel = server.accept(); 
  58. // 設定成非阻塞
  59.                     channel.configureBlocking(false); 
  60. //在這裡可以給客戶端傳送資訊哦
  61.                     channel.write(ByteBuffer.wrap(new String("向客戶端傳送了一條資訊").getBytes())); 
  62. //在和客戶端連線成功之後,為了可以接收到客戶端的資訊,需要給通道設定讀的許可權。
  63.                     channel.register(this.selector, SelectionKey.OP_READ); 
  64. // 獲得了可讀的事件
  65.                 } else if (key.isReadable()) { 
  66.                         read(key); 
  67.                 } 
  68.             } 
  69.         } 
  70.     } 
  71. /**
  72.      * 處理讀取客戶端發來的資訊 的事件
  73.      * @param key
  74.      * @throws IOException
  75.      */
  76. public void read(SelectionKey key) throws IOException{ 
  77. // 伺服器可讀取訊息:得到事件發生的Socket通道
  78.         SocketChannel channel = (SocketChannel) key.channel(); 
  79. // 建立讀取的緩衝區
  80.         ByteBuffer buffer = ByteBuffer.allocate(10); 
  81.         channel.read(buffer); 
  82. byte[] data = buffer.array(); 
  83.         String msg = new String(data).trim(); 
  84.         System.out.println("服務端收到資訊:"+msg); 
  85.         ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes()); 
  86.         channel.write(outBuffer);// 將訊息回送給客戶端
  87.     } 
  88. /**
  89.      * 啟動服務端測試
  90.      * @throws IOException
  91.      */
  92. public static void main(String[] args) throws IOException { 
  93.         NIOServer server = new NIOServer(); 
  94.         server.initServer(8000); 
  95.         server.listen(); 
  96.     }