【译】Java NIO SocketChannel

本文详细介绍了Java NIO中的SocketChannel,包括如何创建、连接、读写数据以及非阻塞模式的使用。同时,文章还讲解了如何利用Selector进行多路复用,提高SocketChannel的效率。

Java NIO的SocketChannel是一个用来连接TCP网络的channel。有两种方式创建:

  1. open一个SocketChannel并连接到internet上的某个服务器。
  2. 当有一个ServerSocketChannel连接来了,就创建一个SocketChannel。

open一个SocketChannel

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

关闭一个SocketChannel

调用close方法就可以关闭:

socketChannel.close();    

从SocketChannel中读数据

通过调用read方法:

ByteBuffer buf = ByteBuffer.allocate(48);

int bytesRead = socketChannel.read(buf);

首先分配一个buffer空间,然后把buffer当作参数传入socketChannel的read方法。返回的int值表明读取了多少长度的字节。如果是-1则表示已经读完或者连接已经关闭。

向SocketChannel中写数据

调用write方法即可,需要一个Buffer作为参数:

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()调用,直到缓冲区没有需要写入的字节为止。

非阻塞模式

这种类型的channel可以设置成非阻塞模式。设置之后,就可以在异步的模式下调用connect、read、write等函数了。

connect()

在非阻塞模式下调用connect方法,可能会在建立连接之前就返回了。判断是否建立连接的依据就是调用finishConnect()方法,类似这样:

socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));

while(! socketChannel.finishConnect() ){
    //wait, or do something else...    
}

write()

在非阻塞模式下调用write方法,可能在还没写任何数据的时候就返回了。因此你需要在一个while循环中调用write()。这和上面的写数据的例子类似。

read()

在非阻塞模式下调用read方法,可能在还没任何数据的情况下就返回了。因此你需要注意返回的int型的值,它表明了这次返回了多少长度的数据。

非阻塞模式下使用Selector

非阻塞模式下SocketChannel的Selector工作的更好。把一个Selector注册到多个SocketChannel中,你可以调用Selector来查看哪些channel已经准备好了。后面会介绍如果在SocketChannel中使用Selector。

 

下一篇:【译】Java NIO ServerSocketChannel

要将 `SocketChannel` 改为 `NioSocketChannel`,通常是在使用 Netty 框架时进行的操作。`NioSocketChannel` 是 Netty 提供的基于 NIOSocketChannel 实现,用于非阻塞 I/O 操作。以下是如何在 Netty 中将 `SocketChannel` 替换为 `NioSocketChannel` 的示例: ### 示例代码 ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; public class NettyClient { private final String host; private final int port; public NettyClient(String host, int port) { this.host = host; this.port = port; } public void start() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) // 使用 NioSocketChannel .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { // 配置管道 } }); ChannelFuture future = bootstrap.connect(host, port).sync(); future.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new NettyClient("localhost", 8080).start(); } } ``` ### 关键点说明 1. **`NioSocketChannel` 的使用**: - 在 `Bootstrap` 中通过 `.channel(NioSocketChannel.class)` 指定使用 `NioSocketChannel`。 - `NioSocketChannel` 是 Netty 提供的基于 NIO 的实现,支持非阻塞 I/O。 2. **`EventLoopGroup`**: - 使用 `NioEventLoopGroup` 来处理 I/O 操作,它与 `NioSocketChannel` 配合使用。 3. **`ChannelInitializer`**: - 尽管 `ChannelInitializer` 的泛型仍然是 `SocketChannel`,但实际运行时会被替换为 `NioSocketChannel`。 ### 注意事项 - 确保项目中已经引入了 Netty 的依赖(如 `netty-all`)。 - 如果之前使用的是阻塞式的 `SocketChannel`,改为 `NioSocketChannel` 后需要调整代码逻辑以适应非阻塞模式。 ### 相关问题 1. `NioSocketChannel` 和 `OioSocketChannel` 的主要区别是什么? 2. 在 Netty 中,`NioEventLoopGroup` 的作用是什么? 3. 如何配置 `NioSocketChannel` 的 TCP 参数(如 `SO_BACKLOG`)? 4. 在非阻塞模式下,如何处理 `NioSocketChannel` 的读写事件? 5. Netty 的 `Bootstrap` 和 `ServerBootstrap` 有什么区别?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值