Netty客户端接入流程NioSocketChannel创建解析
目录
- NioSocketChannel的创建
- 回到上一小节的read()方法
- 我们首先看readBuf
- jdk底层相关的内容
- 跟到父类构造方法中
- 我们跟进其构造方法
NioSocketChannel的创建
回到上一小节的read()方法
public void read() {//必须是NioEventLoop方法调用的, 不能通过外部线程调用assert eventLoop().inEventLoop(); //服务端channel的configfinal ChannelConfig config = config(); //服务端channel的pipelinefinal ChannelPipeline pipeline = pipeline(); //处理服务端接入的速率final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle(); //设置配置allocHandle.reset(config); boolean closed = false; Throwable exception = null; try {try {do {//创建jdk底层的channel//readBuf用于临时承载读到链接int localRead = doReadMessages(readBuf); if (localRead == 0) {break; }if (localRead < 0) {closed = true; break; }//分配器将读到的链接进行计数allocHandle.incMessagesRead(localRead); //连接数是否超过最大值} while (allocHandle.continueReading()); } catch (Throwable t) {exception = t; }int size = readBuf.size(); //遍历每一条客户端连接for (int i = 0; i < size; i ++) {readPending = false; //传递事件, 将创建NioSokectChannel进行传递//最终会调用ServerBootstrap的内部类ServerBootstrapAcceptor的channelRead()方法pipeline.fireChannelRead(readBuf.get(i)); }readBuf.clear(); allocHandle.readComplete(); pipeline.fireChannelReadComplete(); //代码省略} finally {//代码省略}}
我们继续剖析int localRead = doReadMessages(readBuf)这一部分逻辑
我们首先看readBuf
private final List
这里只是简单的定义了一个ArrayList, doReadMessages(readBuf)方法就是将读到的链接放在这个list中, 因为这里是NioServerSocketChannel所以这走到了NioServerSocketChannel的doReadMessage()方法
跟到doReadMessage()方法中:
protected int doReadMessages(Listbuf) throws Exception {//根据当前jdk底层的serverSocketChannel拿到jdk底层channelSocketChannel ch = javaChannel().accept(); try {if (ch != null) {//封装成一个NioSokectChannel扔到buf中buf.add(new NioSocketChannel(this, ch)); return 1; }} catch (Throwable t) {//代码省略}return 0; }
jdk底层相关的内容
首先根据jdk的ServerSocketChannel拿到jdk的Channel, 熟悉Nio的小伙伴应该不会陌生
封装成一个NioSokectChannel扔到Readbuf中
这里的NioSocketChannel是对jdk底层的SocketChannel的包装, 我们看到其构造方法传入两个参数, this代表当前NioServerSocketChannel, ch代表jdk的SocketChannel
我们跟到NioSocketChannel的构造方法中:
public NioSocketChannel(Channel parent, SocketChannel socket) {super(parent, socket); config = new NioSocketChannelConfig(this, socket.socket()); }
这里看到调用了父类构造方法, 传入两个参数, parent代表创建自身channel的, NioServerSocketChannel, socket代表jdk底层的socketChannel
跟到父类构造方法中
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) { super(parent, ch, SelectionKey.OP_READ); }
其中SelectionKey.OP_READ代表其监听事件是读事件
继续跟父类的构造方法:
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {super(parent); this.ch = ch; this.readInterestOp = readInterestOp; try {//设置为非阻塞ch.configureBlocking(false); } catch (IOException e) {//代码省略}}
这里初始化了自身成员变量ch, 就是jdk底层的SocketChannel, 并初始化了自身的监听事件readInterestOp, 也就是读事件
ch.configureBlocking(false)这一步熟悉nio的小伙伴也不陌生, 就是将jdk的SocketChannel设置为非阻塞
我们继续跟到父类构造方法中:
protected AbstractChannel(Channel parent) {this.parent = parent; id = newId(); unsafe = newUnsafe(); pipeline = newChannelPipeline(); }
这里初始化parent, 也就是创建自身的NioServerSocketChannel, 并为自身创建了唯一id
初始化unsafe, 我们跟到newUnsafe()方法中
由于此方法是NioEventLoop调用的, 所以会走到其父类AbstractNioByteChannel的newUnsafe()
跟到newUnsafe()中:
protected AbstractNioUnsafe newUnsafe() {return new NioByteUnsafe(); }
这里创建了NioByteUnsafe对象, 所以NioSocketChannel对应的unsafe是NioByteUnsafe
继续往下跟, 我们看到其初始化了pipeline, 有关pipline的知识, 我们会在下一章节中讲到
回到NioSocketChannel中的构造方法:
public NioSocketChannel(Channel parent, SocketChannel socket) {super(parent, socket); config = new NioSocketChannelConfig(this, socket.socket()); }
同NioServerSocketChannel一样, 这里也初始化了一个Config属性, 传入两个参数, 当前NioSocketChannel自身和jdk的底层SocketChannel的socket对象
我们跟进其构造方法
private NioSocketChannelConfig(NioSocketChannel channel, Socket javaSocket) {super(channel, javaSocket); }
同样, 这个类是NioSocketChannel的内部类
继续跟父类构造方法:
public DefaultSocketChannelConfig(SocketChannel channel, Socket javaSocket) {super(channel); if (javaSocket == null) {throw new NullPointerException("javaSocket"); }//保存当前javaSocketthis.javaSocket = javaSocket; //是否禁止Nagle算法if (PlatformDependent.canEnableTcpNoDelayByDefault()) {try {setTcpNoDelay(true); } catch (Exception e) {}}}
这里保存了SocketChannel的socket对象, 并且默认的情况禁止了Nagle算法, 有关Nagle, 感兴趣的同学可以学习下相关知识
继续跟到父类构造方法中:
public DefaultChannelConfig(Channel channel) {this(channel, new AdaptiveRecvByteBufAllocator()); }
又跟到到了我们熟悉的部分了, 也就是说, 无论NioServerSocketChannel和NioSocketChannel, 最后都会初始化DefaultChannelConfig, 并创建可变ByteBuf分配器, 我们之前小节对此做过详细剖析这里不再赘述, 这部分忘记的内容可以阅读之前小节内容进行回顾
这个分配器什么时候真正分配字节缓冲的呢?我们会在之后的章节进行详细剖析
至此我们剖析完成了NioSocketChannel的初始化过程
【Netty客户端接入流程NioSocketChannel创建解析】以上就是Netty客户端接入流程NioSocketChannel创建源码解析的详细内容,更多关于Netty客户端接入流程NioSocketChannel的资料请关注脚本之家其它相关文章!
推荐阅读
- TCP客户端和服务端的互通信息
- Netty源码分析NioEventLoop执行select操作入口
- 敲!敲!这是你找的简洁又直观的SSH客户端吗()
- 项目实战!接入分布式定时任务框架
- Java笔记之从IO模型到Netty框架学习初识篇
- 关于OAuth2.0|关于OAuth2.0 Authorization Code + PKCE flow在原生客户端(Native App)下集成的一点思考
- BSN-DDC 基础网络关键知识点(三)接入DDC网络
- Docker下安装Mongo4.2及客户端工具连接Mongo
- vue全局接入百度地图的实现示例
- MySQL复习