SocketChannel 是連接到 TCP 網絡套接字的 Channel,相當於 Java 網絡編程中的 Socket。有兩種創建 SocketChannel 的方式:
- 手動開啓一個 SocketChannel 並連接到因特網上的一個服務器
- 當傳入的連接到達 ServerSocketChannel 時或者說 ServerSocketChannel 新進來一個連接的時候會創建一個 SocketChannel
1、開啓一個 SocketChannel
示例如下:
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
2、關閉一個 SocketChannel
通過調用 SocketChannel 的 close() 方法可以關閉這個 SocketChannel:
socketChannel.close();
3、從 SocketChannel 中讀取數據
可以通過調用 SocketChannel 的 read() 或其重載方法讀取 SocketChannel 中的數據:
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);
首先分配一個 Buffer,數據從 SocketChannel 中讀取後寫入該 Buffer。然後調用 SocketChannel.read() 方法達到上述目的,該方法的返回值顯示了向指定的 Buffer 中寫入了多少個字節的數據,如果返回 -1 表示數據讀取結束(連接被關閉)。
4、向 SocketChannel 中寫數據
調用 SocketChannel 的 write() 方法可以向 SocketChannel 中寫數據,需要傳入一個 Buffer,表示將該 Buffer 中的數據寫入到 SocketChannel 中:
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()) {
channel.write(buf);//將Buffer中的數據寫入到SocketChannel中
}
注意把 SocketChannel.write() 方法的調用放在一個 while 循環中。由於無法保證有多少字節會寫入到 SocketChannel 中,因此需要重複調用 write() 方法直到沒有數據可以寫爲止。
5、非阻塞模式
可以將 SocketChannel 設置爲非阻塞的。這樣的話,就可以使 connect()、read()、write() 這些方法異步執行。
①connect()
如果 SocketChannel 設置爲了非阻塞的,在調用 connect() 方法的時候,這個方法可能會在連接建立之前返回。要確定連接是否已經建立,可以調用 finishConnect() 方法,示例如下:
socketChannel.configureBlocking(false);//將SocketChannel設置爲非阻塞的
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));//建立連接(異步)
while(!socketChannel.finishConnect() ){//若連接尚未創建
//等待,或者執行別的操作
}
②write()
非阻塞模式下 write() 方法可能在還沒有寫入任何數據時返回。因此需要在一個循環中調用 write(),我們前面的示例中一直是這麼做的,因此對於 write() 來說不需要做什麼改動。
③read()
在非阻塞模式下 read() 方法可能會在還沒有讀取任何數據的情況下返回。因此需要關注該方法的返回值,該返回值表明了讀取了多少字節的數據。
④非阻塞模式下的 Selector
非阻塞模式的 SocketChannel 和 Selector 搭配更好,將一個或多個 SocketChannel 註冊到一個 Selector 中,然後通過輪詢這個 Selector 察看是否有準備好讀寫的 Channel,至於 Selector 和 SocketChannel 怎麼搭配使用後面會有詳細的講述。