先打個(gè)小廣告,關(guān)注辛星教程,我的微信號(hào)xinxing0913,該項(xiàng)目源碼所在的github地址: https://github.com/xinxing0913/xinxing-nio-guide。
前面我們介紹的操作都是對(duì)于本地文件的操作,接下來我們就要進(jìn)行網(wǎng)絡(luò)相關(guān)的操作了。這里我們經(jīng)常使用的兩個(gè)Channel是SocketChannel與ServerSocketChannel。
SocketChannel是用于TCP網(wǎng)絡(luò)連接的套接字接口,它一般用來作為客戶端的套接字,它有點(diǎn)類似于java中的Socket類。我們使用它的一般套路是:
SocketChannel channel = SocketChannel.open();
channel.connect(xxx);
我們可以用它的read方法來讀取數(shù)據(jù),我們也可以用它的write方法來寫入數(shù)據(jù),我們可以用它的configureBlocking(false)方法來設(shè)置為非阻塞模式。不過需要說明的是,由于真實(shí)場景下讀取數(shù)據(jù)可能不是一次性能完成,因此可能需要在一個(gè)循環(huán)中進(jìn)行讀取。
ServerSocketChannel是用于監(jiān)聽TCP連接的通道,它類似于java網(wǎng)絡(luò)編程中的ServerSocket,它的一般使用道路是:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(xxx);
while (true) {
SocketChannel client = serverSocketChannel.accept();
// 其他操作
client.close();
}
這里我們首先調(diào)用它的open方法來打開一個(gè)通道,然后我們調(diào)用其bind()方法來綁定到某個(gè)地址上,然后我們通過accept()方法來每次獲取一個(gè)客戶端的連接,別忘記在操作完客戶端之后要關(guān)閉。
我們接下來就來編寫一個(gè)nio的客戶端和服務(wù)端通信的范例把,首先是client代碼的范例:
/**
* 基于nio實(shí)現(xiàn)的非阻塞客戶端
*/
public class Demo9 {
public static void main(String[] args) throws Exception{
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false); // 設(shè)置為非阻塞
socketChannel.connect(new InetSocketAddress(8080));
socketChannel.finishConnect(); // 等待連接完成
// 向服務(wù)端發(fā)送一段文本
byte[] bytes = "hello 辛星".getBytes();
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
socketChannel.write(byteBuffer);
// 最多只接受服務(wù)端的1024個(gè)字節(jié)
ByteBuffer responseBuffer = ByteBuffer.allocate(1024);
socketChannel.read(responseBuffer);
System.out.println("服務(wù)端響應(yīng)的數(shù)據(jù):" + new String(responseBuffer.array()));
}
}
需要特殊說明的是,我們調(diào)用了finishConnect()方法來等待連接完成,然后才發(fā)的消息,如果連接未完成就發(fā)消息的話,可能會(huì)拋出NotYetConnectedException異常。
然后我們來編寫一個(gè)nio的服務(wù)端的范例把,如下所示:
/**
* 基于nio實(shí)現(xiàn)的非阻塞服務(wù)端
*/
public class Demo10 {
private static final byte[] bytes = "received !!".getBytes();
public static void main(String[] args) throws Exception {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
System.out.println("服務(wù)端已啟動(dòng),開始接受客戶端連接...");
while (true) {
SocketChannel socketChannel = serverSocketChannel.accept();
if (!Objects.isNull(socketChannel)) {
// 最多只接受客戶端的1024個(gè)字節(jié)
ByteBuffer requestBuffer = ByteBuffer.allocate(1024);
socketChannel.read(requestBuffer);
System.out.println("客戶端輸入的內(nèi)容:" + new String(requestBuffer.array()));
// 給客戶端寫入數(shù)據(jù),然后關(guān)閉連接
// 發(fā)送給客戶端的文本信息
ByteBuffer responseBuffer = ByteBuffer.wrap(bytes);
socketChannel.write(responseBuffer);
socketChannel.close();
}
}
}
}
然后我們首先啟動(dòng)服務(wù)器,我們看到如下所示的效果:
然后我們啟動(dòng)客戶端,我們會(huì)看到如下效果:
然后我們的服務(wù)端就會(huì)收到一次處理連接的信息,如下所示:
對(duì)于基于TCP的通信操作,我們就介紹到這里啦。