Netty服务端接受客户端连接请求源码分析

Netty服务端接受客户端连接请求源码分析

前一篇,提到NioServerSocketChannel注册到eventloop中,eventloop就是接受客户端请求的代码。

eventloop作用是一个不断地循环,循环主要做三件事情:

1.有条件地等待Nio事件

2.处理Nio事件

3.处理队列中的任务

我们找到run代码里的processSelectedKeys(),这里是处理各种事件的。追踪发现最后调用的是private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) ;我们看看代码。

private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
        final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
        if (!k.isValid()) {
            final EventLoop eventLoop;
            try {
                eventLoop = ch.eventLoop();
            } catch (Throwable ignored) {
                return;
            }
            if (eventLoop != this || eventLoop == null) {
                return;
            }
            unsafe.close(unsafe.voidPromise());
            return;
        }

        try {
            int readyOps = k.readyOps();
            if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
                int ops = k.interestOps();
                ops &= ~SelectionKey.OP_CONNECT;
                k.interestOps(ops);

                unsafe.finishConnect();
            }
            if ((readyOps & SelectionKey.OP_WRITE) != 0) {
                // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
                ch.unsafe().forceFlush();
            }

            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                // 这里是处理OP_ACCEPT事件的
                unsafe.read();
            }
        } catch (CancelledKeyException ignored) {
            unsafe.close(unsafe.voidPromise());
        }
    }

点进去NioMeesageUnsafe的read方法,里面调用了NioServerSocketChannel的doReadMessages(List buf)。

protected int doReadMessages(List<Object> buf) throws Exception {
        // 接受一个连接,底层就是JDK的accepet
        SocketChannel ch = SocketUtils.accept(javaChannel());

        try {
            if (ch != null) {
                // 将接收的socketChannel放入list返回
                buf.add(new NioSocketChannel(this, ch));
                return 1;
            }
        } catch (Throwable t) {
            logger.warn("Failed to create a new channel from an accepted socket.", t);

            try {
                ch.close();
            } catch (Throwable t2) {
                logger.warn("Failed to close a socket.", t2);
            }
        }

        return 0;
    }

之后将buf中循环地调用pipeline.fireChannelRead(buf.get(i));

下面分析pipeline的fireChannelRead(Object msg) 方法

@Override
    public final ChannelPipeline fireChannelRead(Object msg) {
        // head是pipeline的头节点,是HeadContext实例
        AbstractChannelHandlerContext.invokeChannelRead(head, msg);
        return this;
    }

// 最后我们追到这个函数
private void invokeChannelRead(Object msg) {
        if (invokeHandler()) {
            try {
                // ctx是handler的包装类,所以我们直接看HeadConxtex的handler的channelRead
                ((ChannelInboundHandler) handler()).channelRead(this, msg);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            fireChannelRead(msg);
        }
    }

// HeadContext的handler就是它本身,所以我们直接看HeadContext的channelRead
@Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            // 发现它调用的ctx的fireChannelRead
            ctx.fireChannelRead(msg);
        }

// ctx的fireChannelRead(Object)方法如下
@Override
    public ChannelHandlerContext fireChannelRead(final Object msg) {
        // findConrtextInboud()是找到当前ctx在pipeline的下一个
        //invokeChannelRead即又回到了第一个函数那,又重新执行一遍上面的逻辑
        // 所以,fireChannelRead的传递机制如下: 每个handler处理完之后调用ctx.fireChannelRead()
        // 从而达到传递给下一个ctx的目的
        invokeChannelRead(findContextInbound(), msg);
        return this;
    }

前一篇文章中,我们知道NioServerSocketChannel的pipeline是由head,LoggingHandler,ServerBootstrapAcceptor,tail组成。

ServerBootstrapAcceptor就是将客户端channel注册到从reactor的代码,其他handler都不是很重要。

下面看看ServerBootstrapAcceptor的channelRead方法

public void channelRead(ChannelHandlerContext ctx, Object msg) {
            // msg就是NioSocketChannel
            final Channel child = (Channel) msg;
            // 给NioSocketChannel设置handler
            child.pipeline().addLast(childHandler);

            setChannelOptions(child, childOptions, logger);

            for (Entry<AttributeKey<?>, Object> e: childAttrs) {
                child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
            }

            try {
                // 将NioSocketChannel注册到workGroup中
                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);
            }
        }

这里的childGroup.register(Channel)追踪进去和前文的regist一样,也就是说此时,该channel(NioSocketChannel)的事件已经注册到NioEventLoop中了。eventloop的任务之一就是select各种事件,自然包括客户端的可读事件,由此开始了服务端与客户端的数据传输。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值