首页 文章详情

Netty客户端发起连接过程注意点

Netty历险记 | 212 2021-04-02 15:18 0 0 0
UniSMS (合一短信)

使用Netty创建客户端的时候, 和创建服务端类似, 也需要经过创建-初始化-注册这三步, 最后一步也最重要就是连接操作

io.netty.bootstrap.Bootstrap#connect(java.net.SocketAddress)



创建就是创建NioSocketChannel, 同时也会创建unsafe,pipeline,config等. 还会设置一个感兴趣的SelectionKey.OP_READ 读事件属性, 此时也仅仅是把OP_READ保存到一个属性上.

初始化就是给channel设置一些option和attribute.

注册就是将channel注册到对应的NioEventLoop的selector上.

这个连接操作会调用到JDK的channel.connect方法, 然而连接操作实际就是向服务端发启TCP三次握手, 握手是有网络延时的, 而Netty是非阻塞的网络框架. Netty调用connect方法, 发起连接之后就返回了, 但是它会向channel中注册一个感兴趣的连接事件.


源码位置

io.netty.channel.socket.nio.NioSocketChannel#doConnect



等到三次握手完成之后, Netty客户端就会监听到连接事件. (Netty底层会有一个IO线程, 一直轮询着外部的事件)


源码位置

io.netty.channel.nio.NioEventLoop#processSelectedKey(java.nio.channels.SelectionKey, io.netty.channel.nio.AbstractNioChannel)





io.netty.channel.DefaultChannelPipeline.HeadContext#channelActive
io.netty.channel.DefaultChannelPipeline.HeadContext#readIfIsAutoRead
io.netty.channel.DefaultChannelPipeline.HeadContext#read
io.netty.channel.nio.AbstractNioChannel#doBeginRead
protected void doBeginRead() throws Exception { final SelectionKey selectionKey = this.selectionKey; if (!selectionKey.isValid()) { return; }
readPending = true;
final int interestOps = selectionKey.interestOps(); if ((interestOps & readInterestOp) == 0) { // 设置之前保存起来的事件, 例如OP_READ selectionKey.interestOps(interestOps | readInterestOp); }}


再经过以上四个主要方法, 最后就会设置感兴趣的OP_READ事件了. 这样客户端才可以读取数据.


【总结】

客户端在向服务器发起连接请求的时候, 由于网络等原因, 连接不会马上成功, Netty是非阻塞框架. 因此在发起连接之后就返回了, 同时设置一个感兴趣的OPCONNECT事件, 等三次握手成功之后, Netty监听到OPCONNECT事件, 然后才会把设置之前的OP_READ事件, 这个时候客户端才可以读取网络数据.

good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter