【通信】NIO实现+源码解析

目录

1.简介

2.最简demo使用

2.1 网络线程模型图

2.2 demo代码

3 源码分析

3.1 Selector选择器

3.1.1 open()创建实例

3.1.2 select()遍历fd选择就绪

3.2 Channel

3.2.1 总图分类

3.2.2 使用 read读取到buffer

3.2.3 write写入

3.3 Buffer缓冲区

3.3.1 核心字段

3.3.2 demo测试

3.3.3 总结


1.简介

java NIO(Non-blocking IO,非阻塞IO),本质是多路复用,以此提高服务端的并发和吞吐量。 多路复用是一个选择器Selector可以监听多个通道Channel的多种事件,如下图所示。

   

核心概念包括 Selector(选择器)、 Channel(通道)、Buffer(缓冲区),如读、写、Accept事件等。下面我们通过一个最简单的TCP服务端实现demo讲解下NIO的这些组件一般用法。

Channels通道

与Socket等支持非阻塞IO的连接

Buffers缓冲

可由Channel通道直接读取或写入的类数组对象

Selectors

指示Channel通道有IO事件

SelectionKeys

维护IO事件状态和绑定

2.最简demo使用

用nio写个最简单的TCPServer,客户端可以连接服务端,以echo打头的指令可以响应回响,否则响应BAD_REQUEST,效果如图所示

2.1 网络线程模型图

为实现上面的服务效果,设计demo使用主线程接收客户端连接,用ThreadPoolExecutor线程池做异步IO处理。

  1. Acceptor线程(主线程)使用ServerSocketChannel监听8888端口,并将其accept事件注册到选择器上;
  2. 当客户端连接后(如上图的telnet连接),触发accept事件,服务通道接收连接获取对应的SocketChannel,并在其上注册RW读写事件,监听该通道的读写事件
  3. 当发生读写事件,读写线程Reactor线程(EchoServerTask进行相应的读写处理

2.2 demo代码

public class EchoServer {
    private static ExecutorService executor; // 用于异步读写的线程池
    static {
        executor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000));
    }
    public static void main(String[] args) throws IOException {

        ServerSocketChannel ssc = ServerSocketChannel.open();// 静态工厂创建服务通道
        ssc.socket().bind(new InetSocketAddress(8888));
        ssc.configureBlocking(false); // !!一定要
        Selector selector = Selector.open(); // 静态工厂模式
        ssc.register(selector, ssc.validOps()); // 注册该服务通道的Accept操作

        while (true) { // 在选择器上轮询
            int readyCount = selector.select(1000);
            if(readyCount==0){
                continue;
            }
            Set<SelectionKey> selectionKeys = selector.selectedKeys(); // 就绪的事件

            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
            while(keyIterator.hasNext()){
                SelectionKey selectionKey = keyIterator.next();
                if(selectionKey.isValid()){
                    // ServerSocketChannel有连接事件
                    if(selectionKey.isAcceptable()){
                        ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel(); // key与通道关联

                        SocketChannel socketChannel = server.accept(); // 接收连接,获得传输通道
                        socketChannel.configureBlocking(false);
                
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值