Java NIO SocketChannel

Java NIO 套接字管道,原文地址:http://tutorials.jenkov.com/java-nio/socketchannel.html

一个 Java NIO 套接字管道表示一个 TCP 协议的套接字连接。它是 Java 套接字的 NIO 版本。有两种方式可以创建套接字管道:

  1. 开启一个套接字管道并连接上一个服务器端程序
  2. 当服务器端套接字接收到一个连接请求时会创建一个套接字管道

开启一个套接字管道

下面展示了怎么开启一个套接字管道:

1
2
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));

关闭一个套接字管道

你可以通过调用 SocketChannel.close() 方法来关闭一个套接字管道。下面是使用小例子:
socketChannel.close();

从一个套接字管道中读取数据

你可以调用 read() 方法从套接字管道中读取数据。下面是使用小例子:

1
2
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);

首先你需要分配一个字节缓冲区,然后调用 SocketChannel.read() 方法来读出管道中的数据,并写入字节缓冲区中。read() 方法的返回值表示有多少数据写入了缓冲区。如果返回值是 -1,那么表示已经到达了输出流的末尾(连接已经关闭)。

向套接字管道中写入数据

你可以调用 SocketChannel.write() 方法来向套接字管道中写入数据,该方法需要一个缓冲区对象作为参数,正如下面这样:

1
2
3
4
5
6
7
8
9
10
11
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);
}

请注意我们是在 while 循环中调用 SocketChannel.write() 方法的。因为我们不知道缓冲区有多少数据可以写入管道中,所以我们重复调用写入方法直到缓冲区中无数据可读。

非阻塞模式

你可以把套接字管道设置为非阻塞模式,然后你就可以在异步模式下调用 connect()read()以及write() 方法了。

connect()

如果你在非阻塞模式下让套接字管道调用了连接方法,那么这个方法将会在连接建立之前被返回(也就是说会立即返回)。为了判断连接是否建立,你需要调用 finishConnect() 方法,就象这样:

1
2
3
4
5
6
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
while(! socketChannel.finishConnect()){
// wait, or do something else...
}

write()

在非阻塞模式下调用 write() 方法,该方法也会立即返回,返回时可能没有任何写入的数据。因此你需要在一个循环中调用写入方法。正如之前例子所展示的写入方法一样,在这里并没有什么不同,所以我们不再重复写这个例子了。

read()

在非阻塞模式下调用 read() 方法,该方法也会立即返回,返回时可能并没有读出任何数据。因此你需要注意其返回值,它的返回值表示有多少数据读出。

Non-blocking Mode with Selectors

在非阻塞模式下,使用选择器来管理套接字管道是更好的选择。通过在一个选择器上注册一个或多个套接字管道,你可以通过选择器来访问已经处于就绪状态的套接字。怎么使用选择器管理套接字管道我们稍后再详细解释。