1、SocketChannel
Java NIO中的SocketChannel是一個鏈接到TCP網絡套接字的通道。能夠經過如下2種方式建立SocketChannel:服務器
打開一個SocketChannel並鏈接到互聯網上的某臺服務器。
一個新鏈接到達ServerSocketChannel時,會建立一個SocketChannel。網絡
打開 SocketChannel
下面是SocketChannel的打開方式:異步
SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
關閉 SocketChannelsocket
當用完SocketChannel以後調用SocketChannel.close()關閉SocketChannel:spa
socketChannel.close();
從 SocketChannel 讀取數據線程
要從SocketChannel中讀取數據,調用一個read()的方法之一。如下是例子:code
ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = socketChannel.read(buf);
首先,分配一個Buffer。從SocketChannel讀取到的數據將會放到這個Buffer中。blog
而後,調用SocketChannel.read()。該方法將數據從SocketChannel 讀到Buffer中。read()方法返回的int值表示讀了多少字節進Buffer裏。若是返回的是-1,表示已經讀到了流的末尾(鏈接關閉了)。ip
寫入 SocketChannel
寫數據到SocketChannel用的是SocketChannel.write()方法,該方法以一個Buffer做爲參數。示例以下:get
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); }
注意SocketChannel.write()方法的調用是在一個while循環中的。Write()方法沒法保證能寫多少字節到SocketChannel。因此,咱們重複調用write()直到Buffer沒有要寫的字節爲止。
非阻塞模式
能夠設置 SocketChannel 爲非阻塞模式(non-blocking mode).設置以後,就能夠在異步模式下調用connect(), read() 和write()了。
connect()
若是SocketChannel在非阻塞模式下,此時調用connect(),該方法可能在鏈接創建以前就返回了。爲了肯定鏈接是否創建,能夠調用finishConnect()的方法。像這樣:
socketChannel.configureBlocking(false); socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80)); while(! socketChannel.finishConnect() ){ //wait, or do something else... }
write()
非阻塞模式下,write()方法在還沒有寫出任何內容時可能就返回了。因此須要在循環中調用write()。前面已經有例子了,這裏就不贅述了。
read()
非阻塞模式下,read()方法在還沒有讀取到任何數據時可能就返回了。因此須要關注它的int返回值,它會告訴你讀取了多少字節。
非阻塞模式與選擇器
非阻塞模式與選擇器搭配會工做的更好,經過將一或多個SocketChannel註冊到Selector,能夠詢問選擇器哪一個通道已經準備好了讀取,寫入等
2、Java NIO DatagramChannel
Java NIO中的DatagramChannel是一個能收發UDP包的通道。由於UDP是無鏈接的網絡協議,因此不能像其它通道那樣讀取和寫入。它發送和接收的是數據包。
打開 DatagramChannel
下面是 DatagramChannel 的打開方式:
DatagramChannel channel = DatagramChannel.open(); channel.socket().bind(new InetSocketAddress(9999));
這個例子打開的 DatagramChannel能夠在UDP端口9999上接收數據包。
接收數據
經過receive()方法從DatagramChannel接收數據,如:
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
channel.receive(buf);
receive()方法會將接收到的數據包內容複製到指定的Buffer. 若是Buffer容不下收到的數據,多出的數據將被丟棄。
發送數據
經過send()方法從DatagramChannel發送數據,如:
String newData = "New String to write to file..." + System.currentTimeMillis(); ByteBuffer buf = ByteBuffer.allocate(48); buf.clear(); buf.put(newData.getBytes()); buf.flip(); int bytesSent = channel.send(buf, new InetSocketAddress("jenkov.com", 80));
這個例子發送一串字符到」jenkov.com」服務器的UDP端口80。 由於服務端並無監控這個端口,因此什麼也不會發生。也不會通知你發出的數據包是否已收到,由於UDP在數據傳送方面沒有任何保證。
鏈接到特定的地址
能夠將DatagramChannel「鏈接」到網絡中的特定地址的。因爲UDP是無鏈接的,鏈接到特定地址並不會像TCP通道那樣建立一個真正的鏈接。而是鎖住DatagramChannel ,讓其只能從特定地址收發數據。
這裏有個例子:
channel.connect(new InetSocketAddress("jenkov.com", 80));
當鏈接後,也可使用read()和write()方法,就像在用傳統的通道同樣。只是在數據傳送方面沒有任何保證。這裏有幾個例子:
int bytesRead = channel.read(buf); int bytesWritten = channel.write(but);
3、Pipe
Java NIO 管道是2個線程之間的單向數據鏈接。Pipe有一個source通道和一個sink通道。數據會被寫到sink通道,從source通道讀取。
這裏是Pipe原理的圖示:
建立管道
經過Pipe.open()方法打開管道。例如:
Pipe pipe = Pipe.open();
向管道寫數據
要向管道寫數據,須要訪問sink通道。像這樣:
Pipe.SinkChannel sinkChannel = pipe.sink();
經過調用SinkChannel的write()方法,將數據寫入SinkChannel,像這樣:
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()) { sinkChannel.write(buf); }
從管道讀取數據
從讀取管道的數據,須要訪問source通道,像這樣:
Pipe.SourceChannel sourceChannel = pipe.source();
調用source通道的read()方法來讀取數據,像這樣:
ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = sourceChannel.read(buf);
read()方法返回的int值會告訴咱們多少字節被讀進了緩衝區。