我在前面说过了server的启动,差不多可以看到netty nio主要的东西包括了:nioEventLoop,nioMessageUnsafe,channelPipeline,channelHandler等。比较绕的就是handler的顺序:head---->tail,这个也是netty链式管理复杂的地方。这里再说下accept如何接受客户端的connect请求(connect请求跟server启动分析差不多,我就不说了)。

入口就在nioEventLoop中:

private static void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
NioUnsafe unsafe = ch.unsafe();
if(!k.isValid()) {
unsafe.close(unsafe.voidPromise());
} else {
try {
int ignored = k.readyOps();
if((ignored & 17) != 0 || ignored == 0) {
unsafe.read();
if(!ch.isOpen()) {
return;
}
} if((ignored & 4) != 0) {
ch.unsafe().forceFlush();
} if((ignored & 8) != 0) {
int ops = k.interestOps();
ops &= -9;
k.interestOps(ops);
unsafe.finishConnect();
}
} catch (CancelledKeyException var5) {
unsafe.close(unsafe.voidPromise());
} }
}
当OP_ACCEPT事件到达时,就会执行nioMessageUnsafe.read()方法。
一直走下去,最终会执行NioServerSocketChannel中的doReadMessages()方法。
protected int doReadMessages(List<Object> buf) throws Exception {
SocketChannel ch = this.javaChannel().accept(); try {
if(ch != null) {
       // 这里就创建了nioScoketChannel,创建过程类似NioServerSocketChannel,并最终添加到buf list中。
buf.add(new NioSocketChannel(this, ch));
return 1;
}
} catch (Throwable var6) {
logger.warn("Failed to create a new channel from an accepted socket.", var6); try {
ch.close();
} catch (Throwable var5) {
logger.warn("Failed to close a socket.", var5);
}
} return 0;
} 我截取一段代码看看添加socketChannel到list集合中发生了什么?
try {
int size;
try {
do {
size = AbstractNioMessageChannel.this.doReadMessages(this.readBuf);
if(size == 0) {
break;
} if(size < 0) {
closed = true;
break;
}
} while(config.isAutoRead() && this.readBuf.size() < maxMessagesPerRead);
} catch (Throwable var11) {
exception = var11;
} AbstractNioMessageChannel.this.setReadPending(false);
size = this.readBuf.size();
int i = 0; while(true) {
if(i >= size) {
this.readBuf.clear();
pipeline.fireChannelReadComplete();
if(exception != null) {
if(exception instanceof IOException && !(exception instanceof PortUnreachableException)) {
closed = !(AbstractNioMessageChannel.this instanceof ServerChannel);
} pipeline.fireExceptionCaught(exception);
} if(closed && AbstractNioMessageChannel.this.isOpen()) {
this.close(this.voidPromise());
}
break;
}      // 看到这个方法了吧,这是一个inbound事件,当前pipeline的执行顺序是:head---->serverBootstrapAcceptor---->tail
     // 先看看serverBootstrapAcceptor跳转到1
pipeline.fireChannelRead(this.readBuf.get(i));
++i;
}
} finally {
if(!config.isAutoRead() && !AbstractNioMessageChannel.this.isReadPending()) {
this.removeReadOp();
} } 1.这个channelRead是serverBootstrapAcceptor执行的channelRead()
public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel)msg;
// 这个地方添加了childHandler,还记得server启动时指定的childHannel吧?
child.pipeline().addLast(new ChannelHandler[]{this.childHandler});
Entry[] t = this.childOptions;
int len$ = t.length; int i$;
Entry e;
for(i$ = 0; i$ < len$; ++i$) {
e = t[i$]; try {
if(!child.config().setOption((ChannelOption)e.getKey(), e.getValue())) {
ServerBootstrap.logger.warn("Unknown channel option: " + e);
}
} catch (Throwable var10) {
ServerBootstrap.logger.warn("Failed to set a channel option: " + child, var10);
}
} t = this.childAttrs;
len$ = t.length; for(i$ = 0; i$ < len$; ++i$) {
e = t[i$];
child.attr((AttributeKey)e.getKey()).set(e.getValue());
} try {
// 进行注册,注意下这里注册的是childGroup,终于worker线程池开始启动了,且正在执行register任务,跳转到2
this.childGroup.register(child).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if(!future.isSuccess()) {
ServerBootstrap.ServerBootstrapAcceptor.forceClose(child, future.cause());
} }
});
} catch (Throwable var9) {
forceClose(child, var9);
} } 2.AbstractChannel中的register0()方法
这个方法跟之前分析server的register方法一致,我说下大概思路:
2.1 将socketChannel注册到selector中;
2.2 通过触发pipeline.fireChannelRegistered();方法将之前main函数中设置的处理器(还记得上一篇netty源码分析之一中唯一的图片吧,就是那个childHandler,本例中就是MessageRecvChannelInitializer这个handler添加到管道中,并将channelInitializer移除)
2.3 通过调用channelActive,ops设置为READ事件。
2.4 worker线程开始监听我们的read事件了。
2.5 boss线程继续执行OP_ACCEPT事件
private void register0(ChannelPromise promise) {
try {
if(!promise.setUncancellable() || !this.ensureOpen(promise)) {
return;
} boolean t = this.neverRegistered;
AbstractChannel.this.doRegister();
this.neverRegistered = false;
AbstractChannel.this.registered = true;
this.safeSetSuccess(promise);
AbstractChannel.this.pipeline.fireChannelRegistered();
if(t && AbstractChannel.this.isActive()) {
AbstractChannel.this.pipeline.fireChannelActive();
}
} catch (Throwable var3) {
this.closeForcibly();
AbstractChannel.this.closeFuture.setClosed();
this.safeSetFailure(promise, var3);
} } 一个完整的ACCEPT事件执行完毕!

netty源码分析之二:accept请求的更多相关文章

  1. Netty源码分析-- 处理客户端接入请求(八)

    这一节我们来一起看下,一个客户端接入进来是什么情况.首先我们根据之前的分析,先启动服务端,然后打一个断点. 这个断点打在哪里呢?就是NioEventLoop上的select方法上. 然后我们启动一个客 ...

  2. Netty源码分析 (二)----- ServerBootstrap

    BootStrap在netty的应用程序中负责引导服务器和客户端.netty包含了两种不同类型的引导: 1. 使用服务器的ServerBootStrap,用于接受客户端的连接以及为已接受的连接创建子通 ...

  3. Netty源码分析(二):服务端启动

    上一篇粗略的介绍了一下netty,本篇将详细介绍Netty的服务器的启动过程. ServerBootstrap 看过上篇事例的人,可以知道ServerBootstrap是Netty服务端启动中扮演着一 ...

  4. Netty源码分析 (三)----- 服务端启动源码分析

    本文接着前两篇文章来讲,主要讲服务端类剩下的部分,我们还是来先看看服务端的代码 /** * Created by chenhao on 2019/9/4. */ public final class ...

  5. Tomcat源码分析(二)------ 一次完整请求的里里外外

    Tomcat源码分析(二)------ 一次完整请求的里里外外   前几天分析了一下Tomcat的架构和启动过程,今天开始研究它的运转机制.Tomcat最本质就是个能运行JSP/Servlet的Web ...

  6. Netty 源码分析系列(二)Netty 架构设计

    前言 上一篇文章,我们对 Netty做了一个基本的概述,知道什么是Netty以及Netty的简单应用. Netty 源码分析系列(一)Netty 概述 本篇文章我们就来说说Netty的架构设计,解密高 ...

  7. netty源码分析之揭开reactor线程的面纱(二)

    如果你对netty的reactor线程不了解,建议先看下上一篇文章netty源码分析之揭开reactor线程的面纱(一),这里再把reactor中的三个步骤的图贴一下 reactor线程 我们已经了解 ...

  8. Netty源码分析--内存模型(上)(十一)

    前两节我们分别看了FastThreadLocal和ThreadLocal的源码分析,并且在第八节的时候讲到了处理一个客户端的接入请求,一个客户端是接入进来的,是怎么注册到多路复用器上的.那么这一节我们 ...

  9. 一个普通的 Zepto 源码分析(二) - ajax 模块

    一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...

随机推荐

  1. [py]一致性hash原理

    1,可变,不可变 python中值得是引用地址是否变化. 2.可hash 生命周期里不可变得值都可hash 3.python中内置数据结构特点 有序不可变 有序可变 无序可变 无序不可变 5.一致性h ...

  2. 高并发架构系列:MQ消息队列的12点核心原理总结

    消息队列已经逐渐成为分布式应用场景.内部通信.以及秒杀等高并发业务场景的核心手段,它具有低耦合.可靠投递.广播.流量控制.最终一致性 等一系列功能. 无论是 RabbitMQ.RocketMQ.Act ...

  3. easy UI的密码长度以及重复输入验证

    自己些项目的时候找的时候也找了一会,所以存下来下次用的时候可以直接用了. 话不多说,直接上代码 <tr> <td>密码:</td> <td><in ...

  4. UI框架搭建DAY2

    今天的主要任务是完善NormalPanel, 搭建PopupPanel. 在编写PanelManager的过程中,发现了一个bug.昨天把panelPath直接传给了ResourceManager.G ...

  5. Failure to transfer org.apache.maven.plugins:maven-surefire-plugin:pom:2.12.4

    Failure to transfer org.apache.maven.plugins:maven-surefire-plugin:pom:2.12.4 from https://repo.mave ...

  6. SQL Server通过BCP进行大批量数据导入导出

    预置条件: 使用sa帐号登录SQL Server Management Studio,右键点击安全性-登录名-数据库用户名属性,设置服务器角色为sysadmin. 删除已存在的存储过程 String ...

  7. samba服务器笔记 (一)

    Samba安装 samba:主服务包:samba-client:客户端:samba-common:通用工具:samba4-libs:库:samba-winbind:windows域映射:samba-w ...

  8. 零基础快速入门web学习路线(含视频教程)

    下面小编专门为广大web学习爱好者汇总了一条完整的自学线路:零基础快速入门web学习路线(含视频教程)(绝对纯干货)适合初学者的最新WEB前端学习路线汇总! 在当下来说web前端开发工程师可谓是高福利 ...

  9. openvpn 初步使用

    服务端:Centos 7.2 openvpn 2.4.3 客户端:Windows 10 安装包 openvpn的官网在国内访问不了,服务端通过yum安装,客户端在第三方网站下载的 一般的国内源应该都包 ...

  10. Base64 空格,加号问题

    缘由: 在一个项目中,app请求tcpdump日志与记录的日志内容不一致 请求%2B 识别成 + 请求 + 识别成 空格 这个在base64解密的时候会出现异常,base64需要的是加号,而不是空格 ...