如何实现异步 Socket 编程?代码举例讲解

异步Socket编程主要有以下方法:

  1. 使用Selector选择器:
  • Channel注册到Selector上的事件,Selector会异步监听这些事件。
  • 线程阻塞在Selector.select()上,有事件就绪时会继续运行。
  • 这样单线程就可以监听多个Channel,实现异步非阻塞IO。
// 服务端
ServerSocketChannel server = ServerSocketChannel.open(); 
server.bind(new InetSocketAddress(8000));
server.configureBlocking(false);

Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
    selector.select();
    Set<SelectionKey> keys = selector.selectedKeys();
    for (SelectionKey key : keys) {
        if (key.isAcceptable()) {
            SocketChannel channel = server.accept(); 
            channel.configureBlocking(false);
            channel.register(selector, SelectionKey.OP_READ);
        } else if (key.isReadable()) {  
            // 读取客户端数据
        }
    }
}
  1. 使用Java NIO中异步网络编程API:
  • AsynchronousChannelGroup用于管理线程池。
  • AsynchronousSocketChannel用于异步TCP连接。
  • 向Channel注册Read/Write请求,并提供CompletionHandler异步回调。
// 服务端
AsynchronousChannelGroup group = AsynchronousChannelGroup.withThreadPool(Executors.newFixedThreadPool(10));
AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(group);
server.bind(new InetSocketAddress(8000));  

server.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
    @Override
    public void completed(AsynchronousSocketChannel channel, Void attachment) {
        channel.read(null, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer result, ByteBuffer buffer) {
                // 读取数据完成
            }
        });
    }
}); 
  1. 使用异步网络框架:
  • Netty,Vert.x等异步网络框架在底层使用Java NIO,但提供更高级的抽象和功能。
  • 可以简化异步网络编程的难度,更易开发高性能网络应用。
// Netty 服务端
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup)
     .channel(NioServerSocketChannel.class)
     .handler(new LoggingHandler(LogLevel.INFO))
     .childHandler(new ChannelInitializer<SocketChannel>() {
         @Override
         public void initChannel(SocketChannel ch) throws Exception {
             ChannelPipeline p = ch.pipeline();
             // 添加ChannelHandler
         }
     });

    ChannelFuture f = b.bind(8000).sync();
} finally {
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
}

以上就是异步Socket编程的主要方法,相比传统的阻塞IO,可以实现高性能的网络应用程序。正确使用异步IO相比单线程阻塞IO,可以获得更高的吞吐量和更低的延迟。