參考:http://ifeve.com/socket-channel/
原文地址
目錄
- Java NIO教程
- Java NIO 教程(一) 概述
- Java NIO 教程(二) Channel
- Java NIO 教程(三) Buffer
- Java NIO 教程(四) Scatter/Gather
- Java NIO 教程(五) 通道之間的數(shù)據(jù)傳輸
- Java NIO 教程(六) Selector
- Java NIO 教程(七) FileChannel
- Java NIO 教程(八) SocketChannel
- Java NIO 教程(九) ServerSocketChannel
- Java NIO 教程(十) 非阻塞式服務(wù)器
- Java NIO 教程(十一) Java NIO DatagramChannel
- Java NIO 教程(十二) Pipe
- Java NIO 教程(十三) Java NIO vs. IO
- Java NIO 教程(十四) Java NIO Path
- Java NIO 教程(十五) Java NIO Files
- Java NIO 教程(十六) Java NIO AsynchronousFileChannel
Java NIO中的SocketChannel
是一個(gè)連接到TCP網(wǎng)絡(luò)套接字的通道∶车洌可以通過(guò)以下2種方式創(chuàng)建SocketChannel
:
- 打開(kāi)一個(gè)
SocketChannel
并連接到互聯(lián)網(wǎng)上的某臺(tái)服務(wù)器铺坞。 - 一個(gè)新連接到達(dá)
ServerSocketChannel
時(shí),會(huì)創(chuàng)建一個(gè)SocketChannel
华坦。
打開(kāi) SocketChannel
下面是SocketChannel
的打開(kāi)方式:
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
關(guān)閉 SocketChannel
當(dāng)用完SocketChannel
之后調(diào)用SocketChannel.close()
關(guān)閉SocketChannel
:
socketChannel.close();
從 SocketChannel 讀取數(shù)據(jù)
要從SocketChannel
中讀取數(shù)據(jù)间驮,調(diào)用一個(gè)read()
的方法之一驾凶。以下是例子:
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);
首先,分配一個(gè)Buffer
滩褥。從SocketChannel
讀取到的數(shù)據(jù)將會(huì)放到這個(gè)Buffer
中病蛉。
然后,調(diào)用SocketChannel.read()
瑰煎。該方法將數(shù)據(jù)從SocketChannel
讀到Buffer
中铺然。read()
方法返回的int
值表示讀了多少字節(jié)進(jìn)Buffer
里。如果返回的是-1酒甸,表示已經(jīng)讀到了流的末尾(連接關(guān)閉了)魄健。
寫(xiě)入 SocketChannel
寫(xiě)數(shù)據(jù)到SocketChannel
用的是SocketChannel.write()
方法,該方法以一個(gè)Buffer
作為參數(shù)插勤。示例如下:
String newData = "New String to write to file..." + System.currentTimeMillis();
//生成Buffer沽瘦,并向Buffer中寫(xiě)數(shù)據(jù)
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
//切換buffer為讀模式
buf.flip();
while(buf.hasRemaining()) {
channel.write(buf);
}
注意SocketChannel.write()
方法的調(diào)用是在一個(gè)while
循環(huán)中的革骨。write()
方法無(wú)法保證能寫(xiě)多少字節(jié)到SocketChannel
。所以析恋,我們重復(fù)調(diào)用write()
直到Buffer
沒(méi)有要寫(xiě)的字節(jié)為止良哲。
非阻塞模式
可以設(shè)置 SocketChannel
為非阻塞模式(non-blocking mode
).設(shè)置之后,就可以在異步模式下調(diào)用connect()
, read()
和write()
了助隧。
connect()
如果SocketChannel
在非阻塞模式下筑凫,此時(shí)調(diào)用connect()
,該方法可能在連接建立之前就返回了并村。為了確定連接是否建立巍实,可以調(diào)用finishConnect()
的方法。像這樣:
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
while(! socketChannel.finishConnect() ){
//wait, or do something else...
}
write()
非阻塞模式下橘霎,write()
方法在尚未寫(xiě)出任何內(nèi)容時(shí)可能就返回了蔫浆。所以需要在循環(huán)中調(diào)用write()
殖属。前面已經(jīng)有例子了姐叁,這里就不贅述了。
read()
非阻塞模式下,read()
方法在尚未讀取到任何數(shù)據(jù)時(shí)可能就返回了洗显。所以需要關(guān)注它的int
返回值外潜,它會(huì)告訴你讀取了多少字節(jié)。
非阻塞模式與選擇器
非阻塞模式與選擇器搭配會(huì)工作的更好挠唆,通過(guò)將一或多個(gè)SocketChannel
注冊(cè)到Selector
处窥,可以詢(xún)問(wèn)選擇器哪個(gè)通道已經(jīng)準(zhǔn)備好了讀取,寫(xiě)入等玄组。Selector
與SocketChannel
的搭配使用會(huì)在后面詳講滔驾。