我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情
在本文,我们将以实操的形式,来一步一步分析netty是怎么检测新连接和创建客户端连接的以及初始化和注册的
一、检测新连接
首先我们启动main方法,看下bossGroup
和workerGroup
对应的NioEventLoop
的对象哈希值。
疑问?为什么要看
NioEventLoop
对应的哈希值呢?因为轮询i/o事件以及处理i/o事件都是在NioEventLoop
中进行的,(说白了NioEventLoop
他才是真正干活的)bossGroup
和workerGroup
只是NioEventLoop
的(抽象)或者我觉得叫它NioEventLoop
线程组也可以
上图可以看到
bossGroup里边的NioEventLoop的对象哈希值是: 1337
workerGroup里边的NioEventLoop的对象哈希值是: 1336
我们发起个连接请求,来看看服务端会做些什么事情 服务端(入口在
SingleThreadEventExecutor
类的 run()方法的while(true)循环中,我们跳过select()方法(因为select就是负责 拿到
有 accept/read/write
类的 channel
,并不负责后续的i/o事件处理 )然后我们debug
直接来到processSelectedKey
方法)
从上图可以看出,由于是发起的新连接,所以被 对accept感兴趣的NioServerSocketChannel给监听到。
从上图可以看出,
SelectionKey
里边的attachment
变量其实保存的就是 ch这个对象(这个attachment
后续我们可能会用到,所以我们这里提一嘴),可以看到由于是accept事件 值对应的是16 所以再往下走会进入unsafe.read()
这个方法中
```java public void read() { assert AbstractNioMessageChannel.this.eventLoop().inEventLoop();
ChannelConfig config = AbstractNioMessageChannel.this.config();
ChannelPipeline pipeline = AbstractNioMessageChannel.this.pipeline();
Handle allocHandle = AbstractNioMessageChannel.this.unsafe().recvBufAllocHandle();
allocHandle.reset(config);
boolean closed = false;
Throwable exception = null;
try {
int localRead;
try {
do {
//进行客户端连接(NioSocketChannel)的创建
localRead = AbstractNioMessageChannel.this.doReadMessages(this.readBuf);
if (localRead == 0) {
break;
}
if (localRead < 0) {
closed = true;
break;
}
//计数 用于下边的判断
allocHandle.incMessagesRead(localRead);
} while(allocHandle.continueReading());//判断当前读的新连接数量是否超过上限了(默认一次轮询16个)
} catch (Throwable var11) {
exception = var11;
}
localRead = this.read