Netty源码学习-ServerBootstrap启动及事件处理过程

Netty是采用了Reactor模式的多线程版本,建议先看下面这篇文章了解一下Reactor模式: 
http://bylijinnan.iteye.com/blog/1992325  

Netty的启动及事件处理的流程,基本上是按照上面这篇文章来走的 
文章里面提到的操作,每一步都能在Netty里面找到对应的代码 
其中Reactor里面的Acceptor就对应Netty的ServerBootstrap.boss; 
而Reactor里面的Handler就对应Netty里面各ChannelHandler(在worker里面跑) 

由于流程涉及到比较多的类和方法,我提取一下Netty的骨架: 

Java代码   收藏代码
  1. ServerBootstrap.bind(localAddress)  
  2. |-->newServerSocketChannel & fireChannelOpen (得到ServerSocketChannel[server])  
  3.   
  4. -->  
  5. Binder.channelOpen  
  6. |-->Channels.bind(that is : sendDownstream of ChannelState.BOUND)  
  7.   
  8. -->  
  9. In DefaultChannelPipeline, No downstreamHandler, jump to   
  10. NioServerSocketPipelineSink.bind    (关键)  
  11. |-->1.do the REAL java.net.ServerSocket.bind (server绑定端口)  
  12.       2.start bossThread in bossExecutor  
  13.       3.do "accept & dispatch" in a endless loop of bossThread(得到SocketChannel[client])  
  14.          |--> registerAcceptedChannel, start worker in workerPool  
  15.                |-->worker.run  
  16.                      |-->processSelectedKeys(selector.selectedKeys())  
  17.                            |--> read & fireMessageReceived   (开始调用各Handler)  


下面就对照上面的“骨架”,把关键的代码拿出来读一下 
其中关键的步骤,我用“===[关键步骤]===”的形式标记出来了 

Netty的Server端是从ServerBootstrap.bind方法开始的: 
Java代码   收藏代码
  1. public class ServerBootstrap extends Bootstrap {  
  2.   
  3.     public Channel bind(final SocketAddress localAddress) {  
  4.             final BlockingQueue<ChannelFuture> futureQueue =  
  5.                 new LinkedBlockingQueue<ChannelFuture>();  
  6.   
  7.             ChannelHandler binder = new Binder(localAddress, futureQueue);  
  8.   
  9.             ChannelPipeline bossPipeline = Channels.pipeline();  
  10.             bossPipeline.addLast("binder", binder);  
  11.   
  12.             /*===OPEN=== 
  13.             NioServerSocketChannelFactory.newChannel返回一个NioServerSocketChannel 
  14.             在NioServerSocketChannel的构造函数里,调用ServerSocketChannel.open()并触发channelOpen事件 
  15.             这个事件由上面的“binder”来处理并返回Future(非阻塞),详见Binder 
  16.             最后将Future放入futureQueue,以便在接下来的while循环里面取 
  17.             */  
  18.             Channel channel = getFactory().newChannel(bossPipeline);  
  19.               
  20.             // Wait until the future is available.  
  21.             ChannelFuture future = null;  
  22.             boolean interrupted = false;  
  23.             do {  
  24.                 try {  
  25.                     future = futureQueue.poll(Integer.MAX_VALUE, TimeUnit.SECONDS);  
  26.                 } catch (InterruptedException e) {  
  27.                     interrupted = true;  
  28.                 }  
  29.             } while (future == null);  
  30.   
  31.             //处理中断的一种方式,详见《Java并发编程实践》  
  32.             if (interrupted) {  
  33.                 Thread.currentThread().interrupt();  
  34.             }  
  35.   
  36.             // Wait for the future.  
  37.             future.awaitUninterruptibly();  
  38.   
  39.             return channel;  
  40.     }  
  41.   
  42.     //主要是处理channelOpen事件  
  43.     private final class Binder extends SimpleChannelUpstreamHandler {  
  44.   
  45.             private final SocketAddress localAddress;  
  46.             private final BlockingQueue<ChannelFuture> futureQueue;  
  47.             private final Map<String, Object> childOptions =  
  48.                 new HashMap<String, Object>();  
  49.   
  50.             Binder(SocketAddress localAddress, BlockingQueue<ChannelFuture> futureQueue) {  
  51.                 this.localAddress = localAddress;  
  52.                 this.futureQueue = futureQueue;  
  53.             }  
  54.   
  55.             public void channelOpen(  
  56.                     ChannelHandlerContext ctx,  
  57.                     ChannelStateEvent evt) {  
  58.   
  59.                 try {  
  60.                     //处理各种option,例如keep alive,nodelay等等,省略代码  
  61.                 } finally {  
  62.                     ctx.sendUpstream(evt);  
  63.                 }  
  64.   
  65.                 /* 
  66.                 重点在这里 
  67.                 这里bind方法只是触发sendDownstream(ChannelState.BOUND) 
  68.                 而此时pipeline里面还没有ChannelDownstreamHandler(只有一个handler:“binder”): 
  69.                 public void sendDownstream(ChannelEvent e) { 
  70.                     DefaultChannelHandlerContext tail = getActualDownstreamContext(this.tail); 
  71.                     if (tail == null) { 
  72.                         try { 
  73.                             getSink().eventSunk(this, e); 
  74.                             return; 
  75.                         }  
  76.                     } 
  77.                     sendDownstream(tail, e); 
  78.                 } 
  79.                 因此ChannelState.BOUND会去到pipeline里面的sink,在sink里面执行最终的java.net.ServerSocket.bind操作 
  80.                 详见NioServerSocketPipelineSink.bind 
  81.                 */  
  82.                 boolean finished = futureQueue.offer(evt.getChannel().bind(localAddress));  
  83.                 assert finished;  
  84.             }  
  85.             }  
  86. }  


NioServerSocketPipelineSink: 

Java代码   收藏代码
  1. class NioServerSocketPipelineSink extends AbstractNioChannelSink {  
  2.       
  3.      private void bind(  
  4.             NioServerSocketChannel channel, ChannelFuture future,  
  5.             SocketAddress localAddress) {  
  6.         try {  
  7.           
  8.             //在这里执行真正的===BIND===  
  9.             channel.socket.socket().bind(localAddress, channel.getConfig().getBacklog());  
  10.             bound = true;  
  11.   
  12.             Executor bossExecutor =  
  13.                 ((NioServerSocketChannelFactory) channel.getFactory()).bossExecutor;  
  14.               
  15.             //java.net.ServerSocket.bind完成,接下来可以accept了,详见Boss类的run方法  
  16.             //===BOSS start===,放入线程池里跑(bossExecutor)  
  17.             DeadLockProofWorker.start(bossExecutor,  
  18.                     new ThreadRenamingRunnable(new Boss(channel),  
  19.                             "New I/O server boss #" + id + " (" + channel + ')'));  
  20.             bossStarted = true;  
  21.         }   
  22.           
  23.     }  
  24.   
  25.     private final class Boss implements Runnable {  
  26.         private final Selector selector;  
  27.         private final NioServerSocketChannel channel;  
  28.   
  29.         /* 
  30.         ===REGISTER[server]=== 
  31.         注意到每新建一个Boss,就会新建一个selector 
  32.         */  
  33.         Boss(NioServerSocketChannel channel) throws IOException {  
  34.             this.channel = channel;  
  35.             selector = Selector.open();  
  36.             channel.socket.register(selector, SelectionKey.OP_ACCEPT);  
  37.             registered = true;  
  38.             channel.selector = selector;  
  39.         }  
  40.   
  41.         /* 
  42.         ===ACCEPT&DISPATCH=== 
  43.         boss不断地接受Client的连接并将连接成功的SocketChannel交由worker处理 
  44.         */  
  45.         public void run() {  
  46.                         for (;;) {  
  47.                             SocketChannel acceptedSocket = channel.socket.accept();  
  48.                             if (acceptedSocket == null) {  
  49.                                 break;  
  50.                             }  
  51.                               
  52.                             //把acceptedSocket交由worker处理  
  53.                             registerAcceptedChannel(acceptedSocket, currentThread);  
  54.                         }  
  55.         }  
  56.           
  57.         /* 
  58.         这里面的worker(implements Runnable)就相当于“Reactor Pattern”里面“Handler” 
  59.         handler需要两方面信息:selector和acceptedSocket,其中后者已经传递过来了,而selector则 
  60.         在worker.register里新创建一个 
  61.         */  
  62.         private void registerAcceptedChannel(SocketChannel acceptedSocket, Thread currentThread) {  
  63.                 ChannelPipeline pipeline = channel.getConfig().getPipelineFactory().getPipeline();  
  64.                   
  65.                 //从WorkerPool里面取:workers[Math.abs(workerIndex.getAndIncrement() % workers.length)]  
  66.                 //可见worker是re-used的  
  67.                 NioWorker worker = nextWorker();  
  68.                   
  69.                 /* 
  70.                 值得注意的是new NioAcceptedSocketChannel(...)包含了一个关键操作: 
  71.                 将pipeline与channel关联起来,一对一;见AbstractChannel类: 
  72.                     protected AbstractChannel( 
  73.                             Channel parent, ChannelFactory factory, 
  74.                             ChannelPipeline pipeline, ChannelSink sink) { 
  75.  
  76.                         this.parent = parent; 
  77.                         this.factory = factory; 
  78.                         this.pipeline = pipeline; 
  79.  
  80.                         id = allocateId(this); 
  81.  
  82.                         pipeline.attach(this, sink); 
  83.                     } 
  84.                 */  
  85.                 worker.register(new NioAcceptedSocketChannel(  
  86.                         channel.getFactory(), pipeline, channel,  
  87.                         NioServerSocketPipelineSink.this, acceptedSocket,  
  88.                         worker, currentThread), null);  
  89.         }  
  90.     }  
  91. }  


worker.register,主要工作是创建registerTask(implements Runnable)并放入registerTaskQueue 
对应的类是NioWorker 和AbstractNioWorker: 
Java代码   收藏代码
  1. void register(AbstractNioChannel<?> channel, ChannelFuture future) {  
  2.   
  3.     //只是创建Runnable,未启动。在worker的run方法中,processRegisterTaskQueue时候才执行  
  4.        Runnable registerTask = createRegisterTask(channel, future);  
  5.       
  6.     //在start()里面启动worker线程  
  7.        Selector selector = start();  
  8.        boolean offered = registerTaskQueue.offer(registerTask);  
  9.        assert offered;  
  10.   
  11.        if (wakenUp.compareAndSet(falsetrue)) {  
  12.            selector.wakeup();  
  13.        }  
  14.    }  
  15.   
  16.  private Selector start() {  
  17.        synchronized (startStopLock) {  
  18.            if (!started) {  
  19.                 selector = Selector.open();  
  20.               
  21.              //===WORKER start===  
  22.                DeadLockProofWorker.start(executor, new ThreadRenamingRunnable(this"New I/O  worker #" + id));  
  23.            }  
  24.        }  
  25.        return selector;  
  26.    }  
  27.   
  28. private final class RegisterTask implements Runnable {  
  29.        private final NioSocketChannel channel;  
  30.        private final ChannelFuture future;  
  31.        private final boolean server;  
  32.        public void run() {  
  33.            try {  
  34.                synchronized (channel.interestOpsLock) {  
  35.               
  36.                 //===REGISTER[client]===    初始的state(getRawInterestOps)是OP_READ  
  37.                    channel.channel.register(selector, channel.getRawInterestOps(), channel);  
  38.                }  
  39.                fireChannelConnected(channel, remoteAddress);  
  40.         }  
  41.        }  
  42.    }  


worker线程的run操作: 

Java代码   收藏代码
  1.  public void run() {  
  2.         for (;;) {  
  3.                   
  4.                 //===SELECT===  
  5.                 SelectorUtil.select(selector);  
  6.   
  7.                 processRegisterTaskQueue();  
  8.                 processEventQueue();  
  9.                 processWriteTaskQueue();  
  10.                   
  11.                 //在这里面,就会遍历selectedKey并调用相关联的handler  
  12.                 processSelectedKeys(selector.selectedKeys());  
  13.         }  
  14. }     
  15.   
  16. private void processSelectedKeys(Set<SelectionKey> selectedKeys) throws IOException {  
  17.     for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {  
  18.         SelectionKey k = i.next();  
  19.         i.remove();  
  20.         int readyOps = k.readyOps();  
  21.           
  22.         //下面的“与”操作等价于k.isReadable  
  23.         if ((readyOps & SelectionKey.OP_READ) != 0 || readyOps == 0) {  
  24.             //执行读操作  
  25.             if (!read(k)) {  
  26.                 continue;  
  27.             }  
  28.         }  
  29.         //执行写操作  
  30.         if ((readyOps & SelectionKey.OP_WRITE) != 0) {  
  31.             writeFromSelectorLoop(k);  
  32.         }  
  33.     }  
  34. }  
  35.   
  36.     /* 
  37.     主要是两个操作: 
  38.     1.从channel里面读取数据 
  39.     2.读取完成后,fireMessageReceived,从channel(k.attachment) 
  40.      可以得到与它关联的pipeline,从而触发pipeline里面的handler 
  41.     */  
  42.     protected boolean read(SelectionKey k) {  
  43.       
  44.         /* 
  45.         变量“ch”的类型是java.nio.channels.SocketChannel,是“the channel for which this key was created” 
  46.         变量“channel”的类型是org.jboss.netty.channel.socket.nio.NioSocketChannel,是“the attachment for which this key was created” 
  47.         因此,“ch”的作用就是读数据,而“channel”的作用则是取得pipeline后开始处理数据 
  48.          
  49.         但,“channel”似乎是“包含”了“ch”? 
  50.         我们知道,org.jboss.netty.channel.socket.nio.NioSocketChannel是对java.nio.channels.SocketChannel的封装, 
  51.         正如org.jboss.netty.channel.socket.nio.NioServerSocketChannel是对java.nio.channels.ServerSocketChannel的封装 
  52.         而查看RegisterTask的run方法,register并返回SelectionKey: 
  53.         channel.channel.register( 
  54.                             selector, channel.getRawInterestOps(), channel); 
  55.         变量的命名让人糊涂,翻译一下: 
  56.         acceptedNioSocketChannel.channel.register(selector, ops, acceptedNioSocketChannel) 
  57.         注意到acceptedNioSocketChannel.channel的真实类型,其实就是java.nio.channels.SocketChannel, 
  58.         它就是下面代码里的“acceptedSocket”: 
  59.         worker.register(new NioAcceptedSocketChannel( 
  60.                         channel.getFactory(), pipeline, channel, 
  61.                         NioServerSocketPipelineSink.this, acceptedSocket, 
  62.                         worker, currentThread), null); 
  63.         因此,是不是可以认为“channel”与“ch”的关系是: 
  64.         ch = channel.channel 
  65.         */  
  66.           
  67.           
  68.         final SocketChannel ch = (SocketChannel) k.channel();  
  69.         final NioSocketChannel channel = (NioSocketChannel) k.attachment();  
  70.   
  71.         //会根据这一次接收到的数据的大小,来预测下一次接收数据的大小  
  72.         //并以此为依据来决定ByteBuffer的大小  
  73.         final ReceiveBufferSizePredictor predictor =  
  74.             channel.getConfig().getReceiveBufferSizePredictor();  
  75.         final int predictedRecvBufSize = predictor.nextReceiveBufferSize();  
  76.   
  77.         int ret = 0;  
  78.         int readBytes = 0;  
  79.         boolean failure = true;  
  80.   
  81.         ByteBuffer bb = recvBufferPool.acquire(predictedRecvBufSize);  
  82.         try {  
  83.             while ((ret = ch.read(bb)) > 0) {  
  84.                 readBytes += ret;  
  85.                 if (!bb.hasRemaining()) {  
  86.                     break;  
  87.                 }  
  88.             }  
  89.             failure = false;  
  90.         }   
  91.   
  92.         if (readBytes > 0) {  
  93.             bb.flip();  
  94.   
  95.             final ChannelBufferFactory bufferFactory =  
  96.                 channel.getConfig().getBufferFactory();  
  97.             final ChannelBuffer buffer = bufferFactory.getBuffer(readBytes);  
  98.             buffer.setBytes(0, bb);  
  99.             buffer.writerIndex(readBytes);  
  100.   
  101.             recvBufferPool.release(bb);  
  102.   
  103.             // Update the predictor.  
  104.             predictor.previousReceiveBufferSize(readBytes);  
  105.   
  106.             // Fire the event.  
  107.             fireMessageReceived(channel, buffer);  
  108.         }   
  109.         return true;  
  110.     }  
  111.    

http://bylijinnan.iteye.com/blog/1992345
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Netty-WebSocket-Spring-Boot-Starter是一个用于将Websocket集成到Spring Boot应用程序中的库。它使用Netty作为底层框架,提供了一种快速和可靠的方式来处理异步通信。 这个库提供了一种简单的方法来创建Websocket端点,只需要使用注释和POJO类即可。在这些端点上可以添加动态的事件处理程序,以处理连接、断开连接和消息事件等。 此外,Netty-WebSocket-Spring-Boot-Starter还包括了一些安全性的特性,如基于令牌的授权和XSS保护,可以帮助您保持您的Websocket应用程序安全。 总的来说,Netty-WebSocket-Spring-Boot-Starter提供了一种快速和易于使用的方式来构建Websocket应用程序,使得它成为应用程序开发人员的有用工具。 ### 回答2: netty-websocket-spring-boot-starter 是一个开源的 Java Web 开发工具包,主要基于 Netty 框架实现了 WebSocket 协议的支持,同时集成了 Spring Boot 框架,使得开发者可以更加方便地搭建 WebSocket 服务器。 该工具包提供了 WebSocketServer 配置类,通过在 Spring Boot 的启动配置类中调用 WebSocketServer 配置类,即可启动 WebSocket 服务器。同时,该工具包还提供了多种配置参数,如端口号、URI 路径、SSL 配置、认证配置等等,可以根据业务需求进行自定义配置。 此外,该工具包还提供了一些可扩展的接口和抽象类,如 WebSocketHandler、ChannelHandlerAdapter 等,可以通过继承和实现这些接口和抽象类来实现业务逻辑的处理和拓展。 总的来说,netty-websocket-spring-boot-starter 提供了一个高效、简单、易用的 WebSocket 服务器开发框架,可以减少开发者的开发成本和工作量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值