netty源码分析之二:accept请求
我在前面说过了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请求的更多相关文章
- Netty源码分析-- 处理客户端接入请求(八)
这一节我们来一起看下,一个客户端接入进来是什么情况.首先我们根据之前的分析,先启动服务端,然后打一个断点. 这个断点打在哪里呢?就是NioEventLoop上的select方法上. 然后我们启动一个客 ...
- Netty源码分析 (二)----- ServerBootstrap
BootStrap在netty的应用程序中负责引导服务器和客户端.netty包含了两种不同类型的引导: 1. 使用服务器的ServerBootStrap,用于接受客户端的连接以及为已接受的连接创建子通 ...
- Netty源码分析(二):服务端启动
上一篇粗略的介绍了一下netty,本篇将详细介绍Netty的服务器的启动过程. ServerBootstrap 看过上篇事例的人,可以知道ServerBootstrap是Netty服务端启动中扮演着一 ...
- Netty源码分析 (三)----- 服务端启动源码分析
本文接着前两篇文章来讲,主要讲服务端类剩下的部分,我们还是来先看看服务端的代码 /** * Created by chenhao on 2019/9/4. */ public final class ...
- Tomcat源码分析(二)------ 一次完整请求的里里外外
Tomcat源码分析(二)------ 一次完整请求的里里外外 前几天分析了一下Tomcat的架构和启动过程,今天开始研究它的运转机制.Tomcat最本质就是个能运行JSP/Servlet的Web ...
- Netty 源码分析系列(二)Netty 架构设计
前言 上一篇文章,我们对 Netty做了一个基本的概述,知道什么是Netty以及Netty的简单应用. Netty 源码分析系列(一)Netty 概述 本篇文章我们就来说说Netty的架构设计,解密高 ...
- netty源码分析之揭开reactor线程的面纱(二)
如果你对netty的reactor线程不了解,建议先看下上一篇文章netty源码分析之揭开reactor线程的面纱(一),这里再把reactor中的三个步骤的图贴一下 reactor线程 我们已经了解 ...
- Netty源码分析--内存模型(上)(十一)
前两节我们分别看了FastThreadLocal和ThreadLocal的源码分析,并且在第八节的时候讲到了处理一个客户端的接入请求,一个客户端是接入进来的,是怎么注册到多路复用器上的.那么这一节我们 ...
- 一个普通的 Zepto 源码分析(二) - ajax 模块
一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...
随机推荐
- 2018-2019-1 20189203《linux内核原理与分析》第六周作业
第一部分 给Menu OS增加命令 输入命令 rm -rf menu git clone http://github.com/mengning/menu.git make rootfs 查看增加的ti ...
- 修改caffe层的一般流程
https://blog.csdn.net/u012273127/article/details/78701161
- python 匿名函数捕获变量值 (执行时的值)
- 20165215 MySort的实现
MySort的实现 要求 模拟实现Linux下Sort -t : -k 2的功能 要有伪代码,产品代码,测试代码(注意测试用例的设计) import java.util.*; public class ...
- dubbo框架整合常见问题
逆向工程常见问题总结 tomcat7插件启动项目卡在:log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for ...
- 配置firewalld端口转发
题:在系统 system1 设定端口转发,要求: 1.在172.24.8.0/24网络中的系统,访问system1的本地端口 5423 将被转发到 80 2.此设置必须永久有效 答: # 配置转发端口 ...
- UI自动化(六)js
HTML中的三把利器的JS 又称为JavaScript,看着好像和Java有点联系,实际上他和java半毛钱关系都没有,JavaScript和我们学习的Python.Go.Java.C++等,都是一种 ...
- [c/c++] programming之路(17)、高级指针
一.二级指针 二级指针的作用:1.函数改变外部变量指针2.外挂改变一个指针的值 #include<stdio.h> #include<stdlib.h> void main() ...
- 剑指offer(42)和为S的字符串
题目描述 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 输出描述: 对应每个测试案例,输出两个数,小的先输出. 题目 ...
- 20175312 2018-2019-2 《Java程序设计》第3周学习总结
20175312 2018-2019-2 <Java程序设计>第3周学习总结 教材学习内容总结 已依照蓝墨云班课的要求完成了第四章的学习,主要的学习渠道是PPT,和书的课后习题. 总结如下 ...