Netty
2022-06-23 11:53:18 32 举报
部分netty流程
作者其他创作
大纲/内容
boolean wasActive = isActive();doBind(localAddress);
readIfIsAutoRead()
ChannelInitializer
继续调用下一个
epoll在epoll_ctl时直接把eventpoll加入对应的socket(引用指针)等待队列中,接受数据时把有数据的socket加入enevtpoll的就绪列表(rdlist)中,后续唤醒不需要再去遍历所有的socket,只需要获取就绪列表的socket就可以了。
ARP,存储一个MAC地址与本地IP地址的关系,IP地址返回MAC地址RARP:MAC地址返回IP地址
nio是基础缓存读写的所以需要构建一个缓存来接受数据60,1024,65535
判断初始化注册是否成功,有无cause,null,不是UNCANCELLABLE
调用accept会产生一个channel
(interestOps & readInterestOp) == 0->selectionKey.interestOps(interestOps | readInterestOp);
等于原生NIO
ChannelPromise promise = channel.newPromise();
socketA
socketchannel
HeadContext
如果已经调用过handleradd方法就直接read
ctx.fireChannelActive();
移除并添加指针到这个进程的所有socket等待队列中
AbstractBootstrap父类 设置监听事件组group本身设置worker childGroup,并返回自身
调用到ChannelInitializer的added方法时会判断是否在register,现在为true就调用initChannel当前的ctx就是上面提前传入的对象
this.javaSocket = javaSocket
创建一个任务
EPollSelectorImpl
selectkeys
注册accept
new
pipeline.remove(this);
硬中断软中断网卡驱动处理
写入到接收缓冲区再唤醒socket等待队列这里唤醒进程A后进入工作队列,执行到的时候遍历所有socket数据再处理
设置tcp/ip连接参数
如果运营商DNS缓存没有对应的域名就去询问跟域名服务器,返回顶级域名服务器地址
return promise;
往taskqueue丢task
recv()
return regFuture
AbstractChannel.this.eventLoop = eventLoop;
通过DMA拷贝(具体可以查看零拷贝)
会导致失败
这里赋值是16
发送域名连接,通过本地路由NAT转换本地IP为外网IP,本地端口为外网端口。并记录转换的关系
网卡缓冲内存
通过默认的selectotProvider打开一个serverSocketChannel
regFuture.isSuccess()
config().group().register(channel)
!wasActive && isActive()
1
.....
AbstractNioChannel.doBeginRead
构建需要关注的参数封装channel,selector,attr
pendingHandlerCallbackHead = this.pendingHandlerCallbackHead; this.pendingHandlerCallbackHead = null; PendingHandlerCallback task = pendingHandlerCallbackHead
promise.setFailure(regFuture.cause());
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);regFuture.addListener()
bootstrap.bind(new InetSocketAddress(9000))
accept
TailContext
invokeHandlerAddedIfNeeded();ctx.fireChannelRegistered();
先拷贝
pc
描述符fd
还没有完成就添加一个监听器
提前创建一个channel处理器,并在初始化的时候往pipline放入一些处理类
EventLoopGroup bossGroup/workerGroup = new NioEventLoopGroup(3);
for(;;) 循环处理select事件与task任务
调用所有handler的handlerAdded()方法
ChannelHandler handler = config.handler();if (handler != null) ->pipeline.addLast(handler)
handler(.....)
ServerBootstrapAcceptor初始化会设置为true
next.invokeChannelActive();
调用select
findContextInbound(MASK_CHANNEL_ACTIVE)
next.invokeRead();
bind()
font color=\"#f44336\
regFuture.cause() != null
把前面自定义的handler设置到pipline
regFuture = initAndRegister()
子线程已经启动直接调用
创建默认的pipline通道
bind()accept()
输入域名之后需要到DNS解析,但是只有对应的DNS服务器的IP地址,需要获取到MAC地址
socketB
while (task != null) {task.execute(); task = task.next;}
this.implRegister(var4);
socket a
网络
进程A
pipeline.invokeHandlerAddedIfNeeded()
判断channel开启的自动读就调用read()
channel.config().setAutoRead(true);
pipeline.addLast(new font color=\"#f44336\
调用next().register()
调用到unsafe的bind因为server端的unfase是NioMessageUnsafe的对象,而绑定方法定义在abstractchannel
ch.configureBlocking(false);
var4.interestOps(var2);
运营商DNS
紧接着直接一直往下调用
路由DHCP
之前初始化ServerSocketChannel传入=0
.childHandler(new ChannelInitializer<SocketChannel>(){})
(serversocketchannel)key.channel
public NioServerSocketChannel()
FF:FF:FF:FF:FF:FF0.0.0.0UDP广播,DHCP对应MAC地址获取到包解析是DHCP请求,解析。
channel.eventLoop().execute()
自定义的handler
if (firstRegistration)
doBind(localAddress)
3
添加Handler有2种,一种是给服务端Channel设置的,一种是给客户端发起连接后设置的。也就是说存在2个pipeline,分别维护这些Handler
register0中doRegister()后去执行pipline后置处理
false
获取当前拿到的感兴趣值通过验证(调用过read)
channel.pipeline().addLast(new ChannelInitializer<Channel>)
handler().handlerAdded(this);
设置最大读取到缓存的次数,设置接受数据的缓存器
nio默认非阻塞
init(channel);
2
等待队列
final SelectionKey selectionKey = this.selectionKey;readPending = true;
executor.inEventLoop()
selectorKey
根据mark确定出入站事件再获取下一个传递对象
设置感兴趣的类型accpect
cpu
Runnable task = pollTask();safeExecute(task);
DNS
从bossGroup中拿一个channel处理事件,注册到selector中
进程B
如果在子线程就调用头节点channelActive()
abstractChannel
添加监听
pipeline.fireChannelRegistered()
获取当前socketchannel的初始化方法并构建是实例化工厂
最后根据线路进行TCP三次握手,建立HTTP连接
ServerBootstrap bootstrap = new ServerBootstrap();
pollWrapper.add(fd);
调用之前默认pipline添加的类
注册(host,addr,port)checkport检查范围是否有效
路由
rdlist就绪列表
javaChannel就是ch也就是ServerSocketChannel拿到对应的socket
serversocketChannel
((ChannelInboundHandler) handler()).channelRegistered(this);
会调用到tail的read然后又根据tail找到head进行调用
工作队列
调用到DefaultChannelPipeline调用尾节点
font color=\"#212121\
this.ch = ch;this.readInterestOp = readInterestOp;
参考:https://blog.csdn.net/m0_45406092/article/details/117809134
设置ServerSocketChannel设置感兴趣的状态监控
初始化channel
NioEventLoop.run()
callHandlerAddedForAllHandlers()
回调
如果不为空表示channel初始化与创建出现问题
selector
当前是否已经正常绑定端口和channel打开暂时没有
regFuture.isDone()
pipeline = newChannelPipeline();
channel(NioServerSocketChannel.class)
构建服务端的启动容器
pipeline.fireChannelActive();
传入的ChannelInitializer会构建为DefaultChannelHandlerContext然后放入到pipline,如果当前还未调用register0()就设置pendingHandlerCallbackHead的值为当前的对象
封装之前的参数值为map放置到channelattr也会
4
isActive()
NIO
设置自动读取数据channel.config().setAutoRead(true);后面负责客户端接入的handler
ServerBootstrapAcceptor
发送一个ARP报文包含在广播地址的以太网帧中,默认网关获取是ARP报文,解析,返回本地网关路由的MAC地址
initChannel((C) ctx.channel());
int interestOps = selectionKey.interestOps();
网卡
域名对应服务商
循环到当前task就会调用safeExecute(task);
read
执行之前传入的任务
最终因为时jdk8,直接调用到serversocketchannel的bind也就是
tail = new TailContext(this);head = new HeadContext(this);head.next = tail;tail.prev = head;
完成后就执行监听器内容:检测cause错误,有错就往promise里面记录一下没有错误就设置pomise状态并执行dobind0
调用头节点的绑定方法
findContextOutbound(MASK_BIND)
epollCreate()
是否第一次注册重制为false
true
...
接受数据
ROOT DNS
DMA
添加一个channelHandler到pipline(注意:此处还未执行里面的方法,只是添加了一个channelhandler)
channel = channelFactory.newChannel();
pid
ServerBootStrap
进程C
找到头节点
将分配的IP地址,DNS,子网掩码,默认网关返回到PC的MAC地址(链路层解析) ACK
promise.registered()
new InetSocketAddress(9000)
addkey(k)
runAllTasks()
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
new ServerSocketChannelImpl(this);
构建每个事件工作线程池
AdaptiveRecvByteBufAllocator()
注册初始化(异步的)需要是否完成
之前没有启动过之后绑定了端口
发送缓冲区接受缓冲区等待队列
eventpoll
往pipline添加一个handler负责后面的acceptor处理
把当前handler从pipline中去除
eventLoop().execute(task);
顶级域名
链式编程
eventLoop.execute(new Runnable() {@Overridepublic void run() { register0(promise);}});
unsafe.beginRead
往上调用一直到实际实现的方法这里就类似于nio代码封装
创建serverSocketChannel
DefaultChannelHandlerContext
select()
0 条评论
下一页