1. 程式人生 > >java 高效能網路程式設計 NIO

java 高效能網路程式設計 NIO

 伺服器端:

 // 1. 分配一個 ServerSocketChannel 檔案描述符
            serverChannel = ServerSocketChannel.open();

            // 2. 從 ServerSocketChannel裡獲取一個對於的 socket
            serverSocket = serverChannel.socket();

            // 3. 生成一個 Selector
            selector = Selector.open();

            // 4. 把 socket 繫結到埠上
            serverSocket.bind(new InetSocketAddress(iport));

            // 5. serverChannel 未非bolck
            serverChannel.configureBlocking(false);

            // 6. 通過Selector註冊ServerSocketChannel: 只能註冊 accept
            // 而SocketChannel可以註冊CONNENCT,READ,WRITE ; register -> validOps
            // 在各個子類實現不同
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
			try {
				// 獲得IO準備就緒的channel數量
				int n = selector.select();

				// 沒有channel準備就緒,繼續執行
				if (n == 0) {
					continue;
				}

				// 用一個iterator返回Selector的selectedkeys
				Iterator it = selector.selectedKeys().iterator();

				// 處理每一個SelectionKey
				while (it.hasNext()) {
					SelectionKey key = (SelectionKey) it.next();

					// 判斷是否有新的連線到達
					if (key.isAcceptable()) {
						
						// 返回SelectionKey的ServerSocketChannel
						ServerSocketChannel server = (ServerSocketChannel) key
								.channel();
						System.out.println("有連線");
						SocketChannel channel = server.accept();
						
						registerChannel(selector, channel, SelectionKey.OP_READ);
						
						doWork(channel);
					}

					// 判斷是否有資料在此channel裡需要讀取
					if (key.isReadable()) {
						processData(key);
					}
				}

				// 刪除 selectedkeys
				it.remove();

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

 客戶端:

  //開啟socket通道
		SocketChannel socketChannel = SocketChannel.open();
		//設定非阻塞方式
		socketChannel.configureBlocking(false);
		//開啟選擇器
		Selector selector = Selector.open();
		//註冊連線到伺服器socket動作
		socketChannel.register(selector, SelectionKey.OP_CONNECT);
		//連線
		socketChannel.connect( new InetSocketAddress("localhost",9988));
		
		Set<SelectionKey> selectkeySets;
		SelectionKey selectionKey;
		Iterator<SelectionKey> iterator;
		
		//與伺服器通訊通道
		SocketChannel clientChannel ;

	       while(true){
			//選擇一組建,其相應的通道已為I/O操作準備就緒
			//此方法執行處於阻塞模式的選擇操作
			selector.select(TIME_OUT);
			
			//返回此選擇器的已選擇鍵集。
			selectkeySets = selector.selectedKeys();
			iterator = selectkeySets.iterator();
			
			
			while(iterator.hasNext()){
				selectionKey = iterator.next();
				
				if (selectionKey.isConnectable()) {
                                  clientChannel = (SocketChannel)selectionKey.channel();
					// 判斷此通道上是否正在進行連線操作。  
                                  // 完成套接字通道的連線過程。  
					if (clientChannel.isConnectionPending()) {//判斷此通道上是否正在進行連線操作
						clientChannel.finishConnect();  //完成套接字通道的連線過程
                                   
                                  }
                                  clientChannel.register(selector, SelectionKey.OP_WRITE);
                            }else if (selectionKey.isReadable()) {
					clientChannel = (SocketChannel)selectionKey.channel();
					//將緩衝區清空
					receiveBuffer.clear();
					//讀取伺服器傳送來的資料庫到緩衝區
					count = clientChannel.read(receiveBuffer);//count 讀取到的位元組數
					if (count > 0) {
						clientChannel.register(selector, SelectionKey.OP_WRITE);
					}
                            }else if (selectionKey.isWritable()) {
					sendBuffer.clear();
					clientChannel = (SocketChannel)selectionKey.channel();
					clientChannel.write(sendBuffer);
					System.out.println("客戶端向伺服器傳送資料:"+sendText);
					clientChannel.register(selector, SelectionKey.OP_READ);
                            }
                     }
                 }