netty3.2.3源码分析-ClientBootstrap启动分析

转载地址:http://www.blogjava.net/alex-zheng/articles/339908.html

在看完了server端的启动,再来看client端的启动过程是怎么进行的。例子是TelentServer对应的TelentClient
直接看connect方法

public  ChannelFuture connect( final  SocketAddress remoteAddress,  final  SocketAddress localAddress) {

        
if  (remoteAddress  ==   null ) {
            
throw   new  NullPointerException( " remoteAddress " );
        }

        ChannelPipeline pipeline;
        
try  {
            pipeline 
=  getPipelineFactory().getPipeline();
        } 
catch  (Exception e) {
            
throw   new  ChannelPipelineException( " Failed to initialize a pipeline. " , e);
        }

        
//  Set the options.
        
// NioClientSocketChannel构造函数中会触发channelopen
        
// TelnetClientPipelineFactory中的upstreamhandler没有重写channelOpen,这里只是一直往下传递该事件
        Channel ch  =  getFactory().newChannel(pipeline);
        ch.getConfig().setOptions(getOptions());

        
//  Bind.
         if  (localAddress  !=   null ) {
            ch.bind(localAddress);
        }

        
//  Connect.
         return  ch.connect(remoteAddress);
    }
然后执行ch.connect(remoteAddress);
这里是NioClientSocketChannel-->NioSocketChannel-->AbstractChannel
public  ChannelFuture connect(SocketAddress remoteAddress) {
       
return  Channels.connect( this , remoteAddress);
}

public   static  ChannelFuture connect(Channel channel, SocketAddress remoteAddress) {
        
if  (remoteAddress  ==   null ) {
            
throw   new  NullPointerException( " remoteAddress " );
        }
        ChannelFuture future 
=  future(channel,  true );
        channel.getPipeline().sendDownstream(
new  DownstreamChannelStateEvent(
                channel, future, ChannelState.CONNECTED, remoteAddress));
        
return  future;
}

从TelnetClientPipelineFactory的pipeline中由下往上传递CONNECTED事件,这里只有一个StringEncoder-->OneToOneEncoder,其
handleDownstream方法对该事件不做处理,往上传递该事件,执行DefaultChannelHandlerContext.sendDownstream
public   void  sendDownstream(ChannelEvent e) {
            
// 在StringEncoder之前再没有downstreamhandler
            DefaultChannelHandlerContext prev  =  getActualDownstreamContext( this .prev);
            
if  (prev  ==   null ) {
                
try  {
                    getSink().eventSunk(DefaultChannelPipeline.
this , e);
                } 
catch  (Throwable t) {
                    notifyHandlerException(e, t);
                }
            } 
else  {
                DefaultChannelPipeline.
this .sendDownstream(prev, e);
            }
        }
执行NioClientSocketPipelineSink.eventSunk,其中会执行
  private   void  connect(
            
final  NioClientSocketChannel channel,  final  ChannelFuture cf,
            SocketAddress remoteAddress) {
        
try  {
            
// 如果返回true,调用nioworker.register,开始启动nioworker线程处理该channel的读写
            
// 否则,交给boss.register方法,在boss线程中完成连接
             if  (channel.socket.connect(remoteAddress)) {
                channel.worker.register(channel, cf);
            } 
else  {
                
// 为当前clientsocketchannel添加closed的listener
                channel.getCloseFuture().addListener( new  ChannelFutureListener() {
                    
public   void  operationComplete(ChannelFuture f)
                            
throws  Exception {
                        
if  ( ! cf.isDone()) {
                            cf.setFailure(
new  ClosedChannelException());
                        }
                    }
                });
                cf.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                channel.connectFuture 
=  cf;
                
                boss.register(channel);
            }

        } 
catch  (Throwable t) {
            cf.setFailure(t);
            fireExceptionCaught(channel, t);
            channel.worker.close(channel, succeededFuture(channel));
        }
    }

执行boss.register,在boss线程中确保该channel连接成功,这里会启动boss线程
void  register(NioClientSocketChannel channel) {
            
// 在RegisterTask的run方法里注册SelectionKey.OP_CONNECT
            Runnable registerTask  =   new  RegisterTask( this , channel);
            
                
boolean  offered  =  registerTaskQueue.offer(registerTask);
                
assert  offered;
            }

            
if  (wakenUp.compareAndSet( false true )) {
                selector.wakeup();
            }
        }
最后启动boss.run,其中processSelectedKeys里执行connect
private   void  connect(SelectionKey k) {
            NioClientSocketChannel ch 
=  (NioClientSocketChannel) k.attachment();
            
try  {
                
if  (ch.socket.finishConnect()) {
                    k.cancel();
                    
// 连接成功,才在nioworker中启动一个新线程来处理该socketchannel的读写
                    ch.worker.register(ch, ch.connectFuture);
                }
            } 
catch  (Throwable t) {
                ch.connectFuture.setFailure(t);
                fireExceptionCaught(ch, t);
                ch.worker.close(ch, succeededFuture(ch));
            }
        }

之后就是交给nioworker线程来进行数据的发送和接收了。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FastThreadLocal 是 Netty 中的一个优化版 ThreadLocal 实现。与 JDK 自带的 ThreadLocal 相比,FastThreadLocal 在性能上有所提升。 FastThreadLocal 的性能优势主要体现在以下几个方面: 1. 线程安全性:FastThreadLocal 使用了一种高效的方式来保证线程安全,避免了使用锁的开销,使得在高并发场景下性能更好。 2. 内存占用:FastThreadLocal 的内部数据结构更加紧凑,占用的内存更少,减少了对堆内存的占用,提高了内存的利用效率。 3. 访问速度:FastThreadLocal 在访问时,使用了直接索引的方式,避免了哈希表查找的开销,使得访问速度更快。 在 Netty 源码中,FastThreadLocal 主要被用于优化线程的局部变量存储,提高线程之间的数据隔离性和访问效率。通过使用 FastThreadLocal,Netty 在高性能的网络通信中能够更好地管理线程的局部变量,提供更高的性能和并发能力。 引用中提到的代码片段展示了 Netty 中的 InternalThreadLocalMap 的获取方式。如果当前线程是 FastThreadLocalThread 类型的线程,那么就直接调用 fastGet 方法来获取 InternalThreadLocalMap 实例;否则,调用 slowGet 方法来获取。 fastGet 方法中,会先尝试获取线程的 threadLocalMap 属性,如果不存在则创建一个新的 InternalThreadLocalMap,并设置为线程的 threadLocalMap 属性。最后返回获取到的 threadLocalMap。 slowGet 方法中,通过调用 UnpaddedInternalThreadLocalMap.slowThreadLocalMap 的 get 方法来获取 InternalThreadLocalMap 实例。如果获取到的实例为 null,则创建一个新的 InternalThreadLocalMap,并将其设置到 slowThreadLocalMap 中。最后返回获取到的 InternalThreadLocalMap。 综上所述,FastThreadLocal 是 Netty 中为了优化线程局部变量存储而设计的一种高性能的 ThreadLocal 实现。它通过减少锁的开销、优化内存占用和加快访问速度来提升性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [FastThreadLocal源码分析](https://blog.csdn.net/lvlei19911108/article/details/118021402)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Netty 高性能之道 FastThreadLocal 源码分析(快且安全)](https://blog.csdn.net/weixin_33871366/article/details/94653953)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值