netty学习之ChannelSink(NioClientSocketPipelineSink)

这个东西应该是netty里面最难理解的,或者最关键的组件了,这个我会慢慢的进行分析。在Pipeline传送完后,都必须都通ChannelSink进行处理。Sink默认处理了琐碎的操作,例如连接、读写等等。

         ChannelSink这个组件是来处理downstream请求和产生upstream时间的一个组件,是所有io操作的执行者。也就是传输的逻辑层吧。当channel创建的时候就有一个ChannelSink和它想绑定。

        传输层的代码实现一般来说都是比较麻烦的,相比来说客户端的实现一般来说比服务端的实现要简单一些,服务端一般要处理状态变换和数据交换等,我们一点一点来看ChannelSink。

Java代码  收藏代码
  1. public interface ChannelSink {  
  2.   
  3.     /** 
  4.      * Invoked by {@link ChannelPipeline} when a downstream {@link ChannelEvent} 
  5.      * has reached its terminal (the head of the pipeline). 
  6.      */  
  7.     void eventSunk(ChannelPipeline pipeline, ChannelEvent e) throws Exception;  
  8.   
  9.     /** 
  10.      * Invoked by {@link ChannelPipeline} when an exception was raised while 
  11.      * one of its {@link ChannelHandler}s process a {@link ChannelEvent}. 
  12.      */  
  13.     void exceptionCaught(ChannelPipeline pipeline, ChannelEvent e, ChannelPipelineException cause) throws Exception;  
  14.     }  

         接口里面只定义了两个操作,一个是eventSunk,一个是exceptionCaught,eventSunk我不知道怎么翻译,姑且理解为让event处理吧,一般来说应该有一个abstract骨架程序实现,我们就来看吧。

        AbstractChannelSink里面只实现了exceptionCaught,来看一眼:

        

Java代码  收藏代码
  1. public void exceptionCaught(ChannelPipeline pipeline,  
  2.             ChannelEvent event, ChannelPipelineException cause) throws Exception {  
  3.         Throwable actualCause = cause.getCause();  
  4.         if (actualCause == null) {  
  5.             actualCause = cause;  
  6.         }  
  7.   
  8.         fireExceptionCaught(event.getChannel(), actualCause);  
  9.     }  

        这个实际上是向上层报告一个DefaultExceptionEvent的upstream事件。

 

      下来我们就直奔主题来看NioClientSocketPipelineSink这个类吧。

       首先来看局部变量

Java代码  收藏代码
  1. private static final AtomicInteger nextId = new AtomicInteger();  
  2.   
  3.     final int id = nextId.incrementAndGet();  
  4.     final Executor bossExecutor;  
  5.   
  6.     private final Boss[] bosses;  
  7.     private final NioWorker[] workers;  
  8.   
  9.     private final AtomicInteger bossIndex = new AtomicInteger();  
  10.     private final AtomicInteger workerIndex = new AtomicInteger();  

      上面是sink的id,这个地方用到了AtomicInteger。还有Boss和NioWorker,boss的个数现在默认是1,NioWorker的个数是处理器的个数的2倍。后面两个是bossIndex和workerIndex。

     在构造函数里面初始化了Boss和NioWorker

Java代码  收藏代码
  1. NioClientSocketPipelineSink(  
  2.             Executor bossExecutor, Executor workerExecutor,  
  3.             int bossCount, int workerCount) {  
  4.         this.bossExecutor = bossExecutor;  
  5.           
  6.         bosses = new Boss[bossCount];  
  7.         for (int i = 0; i < bosses.length; i ++) {  
  8.             bosses[i] = new Boss(i + 1);  
  9.         }  
  10.           
  11.         workers = new NioWorker[workerCount];  
  12.         for (int i = 0; i < workers.length; i ++) {  
  13.             workers[i] = new NioWorker(id, i + 1, workerExecutor);  
  14.         }  
  15.     }  

 我们接下来看看eventSunk的实现:

 

Java代码  收藏代码
  1. public void eventSunk(  
  2.            ChannelPipeline pipeline, ChannelEvent e) throws Exception {  
  3.        if (e instanceof ChannelStateEvent) {  
  4.            ChannelStateEvent event = (ChannelStateEvent) e;  
  5.            NioClientSocketChannel channel =  
  6.                (NioClientSocketChannel) event.getChannel();  
  7.            ChannelFuture future = event.getFuture();  
  8.            ChannelState state = event.getState();  
  9.            Object value = event.getValue();  
  10.   
  11.            switch (state) {  
  12.            case OPEN:  
  13.                if (Boolean.FALSE.equals(value)) {  
  14.                    channel.worker.close(channel, future);  
  15.                }  
  16.                break;  
  17.            case BOUND:  
  18.                if (value != null) {  
  19.                    bind(channel, future, (SocketAddress) value);  
  20.                } else {  
  21.                    channel.worker.close(channel, future);  
  22.                }  
  23.                break;  
  24.            case CONNECTED:  
  25.                if (value != null) {  
  26.                    connect(channel, future, (SocketAddress) value);  
  27.                } else {  
  28.                    channel.worker.close(channel, future);  
  29.                }  
  30.                break;  
  31.            case INTEREST_OPS:  
  32.                channel.worker.setInterestOps(channel, future, ((Integer) value).intValue());  
  33.                break;  
  34.            }  
  35.        } else if (e instanceof MessageEvent) {  
  36.            MessageEvent event = (MessageEvent) e;  
  37.            NioSocketChannel channel = (NioSocketChannel) event.getChannel();  
  38.            boolean offered = channel.writeBuffer.offer(event);  
  39.            assert offered;  
  40.            channel.worker.writeFromUserCode(channel);  
  41.        }  
  42.    }  
         在这个里面如果是Channel的state变化的事件,则执行相应的操作,最终实现都将交给work去操作,关于worker的这些操作,我们以后会详细的介绍。

这个里面如果是bind操作的话会自己调用bind,如下:

 

Java代码  收藏代码
  1. private void bind(  
  2.             NioClientSocketChannel channel, ChannelFuture future,  
  3.             SocketAddress localAddress) {  
  4.         try {  
  5.             channel.socket.socket().bind(localAddress);  
  6.             channel.boundManually = true;  
  7.             channel.setBound();  
  8.             future.setSuccess();  
  9.             fireChannelBound(channel, channel.getLocalAddress());  
  10.         } catch (Throwable t) {  
  11.             future.setFailure(t);  
  12.             fireExceptionCaught(channel, t);  
  13.         }  
  14.     }  

       这个里面,channel、future、localAddress都是Event里面携带的一些参数,其实这个里面实现了socket的bind操作,并触发一些事件。

最后我们看一下connect的实现:

    

Java代码  收藏代码
  1. private void connect(  
  2.             final NioClientSocketChannel channel, final ChannelFuture cf,  
  3.             SocketAddress remoteAddress) {  
  4.         try {  
  5.             if (channel.socket.connect(remoteAddress)) {  
  6.                 channel.worker.register(channel, cf);  
  7.             } else {  
  8.                 channel.getCloseFuture().addListener(new ChannelFutureListener() {  
  9.                     public void operationComplete(ChannelFuture f)  
  10.                             throws Exception {  
  11.                         if (!cf.isDone()) {  
  12.                             cf.setFailure(new ClosedChannelException());  
  13.                         }  
  14.                     }  
  15.                 });  
  16.                 cf.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);  
  17.                 channel.connectFuture = cf;  
  18.                 nextBoss().register(channel);  
  19.             }  
  20.   
  21.         } catch (Throwable t) {  
  22.             cf.setFailure(t);  
  23.             fireExceptionCaught(channel, t);  
  24.             channel.worker.close(channel, succeededFuture(channel));  
  25.         }  
  26.     }  

    这个里面会执行真正的注册动作,如果失败的话会触发一个connectFuture,这条语句 nextBoss().register(channel)不知道是什么意思?

      关于客户端channelSink就先看到这个地方,接下来会讲解Netty的线程模型,讲完之后我们再回来看服务端的channelSink的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值