netty(十七)源码分析之客户端创建
来源:互联网 发布:芭碧琪面膜怎么样 知乎 编辑:程序博客网 时间:2024/06/06 11:44
相对于服务端,Netty客户端的创建更加复杂,除了要考虑线程模型、异步连接、客户端连接超时等因素外,还需要对连接过程中的各种异常进行考虑。
下面我们直接分析客户端连接操作:
首先要创建和初始化NioSocketChannel,代码如下:
private ChannelFuture doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) { final ChannelFuture regFuture = initAndRegister(); final Channel channel = regFuture.channel(); if (regFuture.cause() != null) { return regFuture; }
从NioEventLoopGroup总获取NioEventLoop,然后使用其作为参数创建NioSocketChannel,代码如下:
Channel createChannel() { EventLoop eventLoop = group().next(); return channelFactory().newChannel(eventLoop); }
初始化Channel之后,将其注册到Selector上,代码如下:
ChannelPromise regFuture = channel.newPromise(); channel.unsafe().register(regFuture);
链路创建成功之后,发起异步TCP连接,代码如下:
private static void doConnect0( final ChannelFuture regFuture, final Channel channel, final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) { // This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up // the pipeline in its channelRegistered() implementation. channel.eventLoop().execute(new Runnable() { @Override public void run() { if (regFuture.isSuccess()) { if (localAddress == null) { channel.connect(remoteAddress, promise); } else { channel.connect(remoteAddress, localAddress, promise); }
由上述代码可以看出,从doConnnect0操作开始,连接操作切换到了Netty的NIO线程NioEventLoop中进行,此时客户端返回,连接操作异步执行。
doConnect0最终调用Headhandler的connect方法,代码如下:
public void connect( ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception { unsafe.connect(remoteAddress, localAddress, promise); }
AbstractNioUnsafe的connect操作如下。
if (doConnect(remoteAddress, localAddress)) { fulfillConnectPromise(promise, wasActive); } else {
需要注意的是,SocketChannel执行connect()操作后有以下三种结果。
(1)连接成功,返回true;
(2)暂时没有连接上,服务端没有返回ACK应答,连接结果不确定,返回false;
(3)连接失败,直接抛出I/O异常。
如果是第二种结果,需要将NioSocketChannel中的selectionKey设置为OP_CONNECT,监听连接结果。
异步连接返回之后,需要判断连接结果,如果连接成功,则触发ChannelActive事件,代码如下(在fulfillConnectPromise方法中):
if (!wasActive && isActive()) { pipeline().fireChannelActive(); }
ChannelActive事件处理最终会将NioSocketChannel中的selectionKey设置为SelectionKey.OP_READ,用于监听网络读操作。
客户端连接超时机制
对于SocketChannel接口,JDK并没有提供连接超时机制,需要NIO框架或者用户自己扩展实现。Netty利用定时器提供了客户端连接超时控制功能,下面我们详细看下该功能:
首先,用户在创建Netty客户端的时候,可以通过ChannelOption.CONNECT_TIMEOUT_MILLIS配置项设置连接超时时间,代码如下:
b.group().opration(ChannelOption.CONNECT_TIMEOUT_MILLIS,3000);
发起连接的同时,启动连接超时检测定时器,代码如下(在AbstractNioChannel中):
connectTimeoutFuture = eventLoop().schedule(new Runnable() { @Override public void run() { ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise; ConnectTimeoutException cause = new ConnectTimeoutException("connection timed out: " + remoteAddress); if (connectPromise != null && connectPromise.tryFailure(cause)) { close(voidPromise()); } } }, connectTimeoutMillis, TimeUnit.MILLISECONDS);
一旦超时定时器执行,说明客户端连接超时,构造连接超时异常,将异常结果设置到connectPromise中,同时关闭客户端连接,释放句柄。
如果在连接超时前获取到连接结果,则删除连接超时定时器,防止其被触发,代码如下:
promise.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isCancelled()) { if (connectTimeoutFuture != null) { connectTimeoutFuture.cancel(false); }
无论连接是否成功,只要获取到连接结果,之后就删除连接超时定时器。
阅读全文
1 0
- netty(十七)源码分析之客户端创建
- Netty 源码分析之 一 客户端创建(Bootstrap )
- netty源码分析之客户端
- netty(五) NIO创建的TimerServer源码分析之客户端
- Netty 源码分析之 一 服务端创建(ServerBootstrap )
- netty(十六)源码分析之服务端创建
- Netty源码分析:客户端连接
- 一起学Netty(十七)netty源码学习之大话java NIO
- netty(四) NIO创建的TimerServer源码分析之服务端
- netty(十)源码分析之ByteBuf
- netty(十三)源码分析之Channel
- netty(十四)源码分析之Unsafe
- netty(十五)源码分析之ChannnelPipeline
- Netty源码分析(二)—客户端初始化
- 【Netty源码分析】客户端connect服务端过程
- Netty系列-客户端启动源码分析
- netty源码分析之ChannelFuture
- netty源码分析之ChannelPipeline
- 4node博客项目系列静态文件的托管
- 计算机类中文核心期刊简介
- 怎样用Python3 写一个爬图片的程序?
- 洛谷P3383 线性筛素数(线性筛)
- STL(十六)hash_map哈希映照容器
- netty(十七)源码分析之客户端创建
- 插入排序及归并排序java代码实现及详细注释
- Git命令上传和克隆工程
- scala类参数修饰符浅析
- MyBatis 01
- FreeType之字形分析(一)
- 堆
- POJ1700Crossing River(过河问题)
- AsyncTask基本使用