【Java NIO 简例】SocketChannel

阅读更多

原文:《Java NIO SocketChannel》

Java NIO 中的 SocketChannel 用于处理 TCP 网络连接。

 

开启 SocketChannel

示例:连接远程服务器

SocketChannel channel = SocketChannel.open();
channel.connect(new InetSocketAddress("abc.xyz", 80));

ServerSocketChannel.accept() 方法也会返回SocketChannel实例。那属于服务端的操作,将在ServerSocketChannel 中说明。

 

关闭 SocketChannel

可直接调用 SocketChannel.close() 方法关闭,也可以 try-with-resources 的方式关闭。

channel.close();

 

读取 SocketChannel 中的数据

可调用 SocketChannel 的 read(ByteBuffer) 方法将数据从channel的当前位置开始,读取到buffer中。

如果返回值为 -1,则表示已读到数据流末尾。

ByteBuffer buffer = ByteBuffer.allocate(1024);
int readByteCount = channel.read(buffer);

 

其它方法:read(ByteBuffer[]) 和 read(ByteBuffer[], int, int) 属于 ScatteringByteChannel 的 数据分散 特性。

 

向 SocketChannel 写数据

可调用 SocketChannel 的 write(ByteBuffer) 方法,将 buffer 当前位置 开始的数据写入 channel。

返回值表示本次写入channel的字节数,可能为0。所以需要放在while循环中,确保buffer中所有数据都被写入channel。

// byte[] data = ...
ByteBuffer buffer = ByteBuffer.allocate(data.length);
buffer.put(data);
buffer.flip();
while (buffer.hasRemaining()) {
  channel.write(buffer);
}

 

其它方法:write(ByteBuffer[]) 和 write(ByteBuffer[], int, int) 属于 GatheringByteChannel 的 数据聚集 特性。

 

非阻塞模式

在非阻塞模式下,SocketChannel 的 connect()、write()、read() 方法都会以异步的模式工作。
即:

  • connect() 方法返回时,连接可能尚未建立;
  • write() 方法返回时,数据可能未写入 channel(其实阻塞模式下也可能未写完);
  • read() 方法返回时,可能未读到数据。

所以需要通过 SocketChannel.finishConnect() 方法判断是否已建立连接;判断 read() 返回的值是否大于0

channel.configureBlocking(false); // 将channel设置为 非阻塞模式
channel.connect(new InetSocketAddress("abc.xyz", 80));

// 等待连接
while (!channel.finishConnect()) {
  // 连接尚未建立,可以做其它事
}

// 连接已建立

 

此外,非阻塞模式的 SocketChannel 更适合与 Selector 搭配使用

你可能感兴趣的:(nio)