Netty原理三:NioEventLoop如何处理客户端连接

文章目录

前言

Netty服务端存在类型为 NioEventLoopGroup 的 Boss 和 Worker,Boss 接收到客户端连接后,将客户端 Channel 注册到 Worker,如下图所示:

Netty原理三:NioEventLoop如何处理客户端连接

原理解析

在 NioEventLoop.java 找到 processSelectedKey 方法,每次有客户端连接时,都会触发该方法

    private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
    	// 客户端连接事件,readyOps = 16
    	int readyOps = k.readyOps();
    		// SelectionKey.OP_CONNECT = 8,因此这里条件不符,跳过
            if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
                int ops = k.interestOps();
                ops &= ~SelectionKey.OP_CONNECT;
                k.interestOps(ops);

                unsafe.finishConnect();
            }

			// SelectionKey.OP_WRITE = 4,这里条件也不符合,跳过
            if ((readyOps & SelectionKey.OP_WRITE) != 0) {
                ch.unsafe().forceFlush();
            }

			// SelectionKey.OP_READ = 1,SelectionKey.OP_ACCEPT = 16,符合条件
            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                unsafe.read();
            }
    }

从最后一个 if 条件,可以得出结论: 客户端连接 或者 客户端发送消息,都会触发服务端的 read 事件。

以本篇分析的客户端连接为例,触发read前会将客户端 NioSocketChannel 对象放到 Message,然后再传到服务端。

在之前的文章我们讲过,ServerBootstrap 启动时会往 Pipeline 添加一个类型为 ServerBootstrapAcceptor 的 Handler,它实现了 channelRead 事件,因此客户端连接时也会触发此处的代码。

	   //ServerBootstrap.java 里面的内部类 ServerBootstrapAcceptor
       @Override
       public void channelRead(ChannelHandlerContext ctx, Object msg) {
       		//这里的msg对象就是客户端的 NioSocketChannel
            final Channel child = (Channel) msg;

			//1.把我们设置的childHandler添加到 NioSocketChannel的Pipeline
            child.pipeline().addLast(childHandler);

            setChannelOptions(child, childOptions, logger);
            setAttributes(child, childAttrs);

            try {
            	//2.把NioSocketChannel注册到WorkerGroup
                childGroup.register(child).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (!future.isSuccess()) {
                            forceClose(child, future.cause());
                        }
                    }
                });
            } catch (Throwable t) {
                forceClose(child, t);
            }
        }

此时 NioSocketChannel 的注册关系如下图所示:

Netty原理三:NioEventLoop如何处理客户端连接

总结

客户端连接时,会把当前NioSocketChannel包装成消息对象,触发服务端 ServerBootstrapAcceptor(Handler)的 channelRead 事件,该事件除了添加用户自定义的 childHandler,还会将 NioSocketChannel 注册到 WorkerGroup

上一篇:WebServices:WSDL的结构分析


下一篇:Markdown基本操作