Netty的服务端怎么和java NIO联系起来的,一直很好奇这块内容,这里跟下代码,下篇文章看下Channel相关的知识。

  1. finalChannelFuture initAndRegister(){
  2. finalChannel channel = channelFactory().newChannel();//
  3. try{
  4. init(channel);
  5. }catch(Throwable t){
  6. channel.unsafe().closeForcibly();//立即关闭通道且不会触发事件
  7. //因为这个通道还没有注册到EventLoop,所以我们需要强制GlobalEventExecutor的使用。
  8. returnnewDefaultChannelPromise(channel,GlobalEventExecutor.INSTANCE).setFailure(t);
  9. }
  10. //注册一个EventLoop
  11. ChannelFuture regFuture = group().register(channel);
  12. //注册失败
  13. if(regFuture.cause()!=null){
  14. if(channel.isRegistered()){
  15. channel.close();
  16. }else{
  17. channel.unsafe().closeForcibly();
  18. }
  19. }
  20. // If we are here and the promise is not failed, it's one of the following cases:
  21. // 程序运行到这里且promise没有失败,可能有如下几种情况
  22. // 1) If we attempted registration from the event loop, the registration has been completed at this point.
  23. // 如果试图注册到一个EventLoop,该注册完成,
  24. // i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
  25. // 2) If we attempted registration from the other thread, the registration request has been successfully
  26. // added to the event loop's task queue for later execution.
  27. // 如果试图注册到其他线程,该注册已经成功,但是没有完成,添加一个事件到任务队列中,等会执行
  28. // i.e. It's safe to attempt bind() or connect() now:
  29. // because bind() or connect() will be executed *after* the scheduled registration task is executed
  30. // because register(), bind(), and connect() are all bound to the same thread.
  31. return regFuture;
  32. }
注意这里的Channle的类型为NioServerSocketChannel类型,group()返回NioEventLoopGroup类型,他继承MultithreadEventLoopGroup,那么看下register的实现:
  1. @Override
  2. publicChannelFutureregister(Channel channel){
  3. return next().register(channel);
  4. }
跟进去是调用了SingleThreadEventLoop类的register方法。实现如下.
  1. @Override
  2. publicChannelFutureregister(finalChannel channel,finalChannelPromise promise){
  3. if(channel ==null){
  4. thrownewNullPointerException("channel");
  5. }
  6. if(promise ==null){
  7. thrownewNullPointerException("promise");
  8. }
  9. channel.unsafe().register(this, promise);
  10. return promise;
  11. }
调用了NioServerSocketChannel的unsafe()的register方法。
  1. @Override
  2. publicfinalvoidregister(EventLoop eventLoop,finalChannelPromise promise){
  3. if(eventLoop ==null){
  4. thrownewNullPointerException("eventLoop");
  5. }
  6. if(isRegistered()){
  7. promise.setFailure(newIllegalStateException("registered to an event loop already"));
  8. return;
  9. }
  10. if(!isCompatible(eventLoop)){
  11. promise.setFailure(
  12. newIllegalStateException("incompatible event loop type: "+ eventLoop.getClass().getName()));
  13. return;
  14. }
  15. AbstractChannel.this.eventLoop = eventLoop;
  16. if(eventLoop.inEventLoop()){
  17. register0(promise);
  18. }else{
  19. try{
  20. eventLoop.execute(newOneTimeTask(){
  21. @Override
  22. publicvoid run(){
  23. register0(promise);
  24. }
  25. });
  26. }catch(Throwable t){
  27. logger.warn(
  28. "Force-closing a channel whose registration task was not accepted by an event loop: {}",
  29. AbstractChannel.this, t);
  30. closeForcibly();
  31. closeFuture.setClosed();
  32. safeSetFailure(promise, t);
  33. }
  34. }
  35. }
对这个eventloop.inEventLoop的理解不是很深刻,有点像android开发里面费时的操作不要放到主线程里面。eventLoop.inEventLoop()表示不在主线程里面。
register的最终实现在,AbstractNioChannel类里面:
  1. @Override
  2. protectedvoid doRegister()throwsException{
  3. boolean selected =false;
  4. for(;;){
  5. try{
  6. selectionKey = javaChannel().register(eventLoop().selector,0,this);
  7. return;
  8. }catch(CancelledKeyException e){
  9. if(!selected){
  10. // Force the Selector to select now as the "canceled" SelectionKey may still be
  11. // cached and not removed because no Select.select(..) operation was called yet.
  12. eventLoop().selectNow();
  13. selected =true;
  14. }else{
  15. // We forced a select operation on the selector before but the SelectionKey is still cached
  16. // for whatever reason. JDK bug ?
  17. throw e;
  18. }
  19. }
  20. }
  21. }
javaChannel()返回Java的Channel对象,eventLoop()返回NioEventLoop对象。里面包含一个selector对象。selectNow是个非阻塞的调用,调用此方法会清除所有以前调用 wakeup 方法所得的结果
Netty的Channel是对JDK中Channel的包装和扩展。
 
注册成功后就需要绑定端口了,
  1. privatestaticvoid doBind0(
  2. finalChannelFuture regFuture,finalChannel channel,
  3. finalSocketAddress localAddress,finalChannelPromise promise){
  4. // This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
  5. // the pipeline in its channelRegistered() implementation.
  6. channel.eventLoop().execute(newRunnable(){
  7. @Override
  8. publicvoid run(){
  9. if(regFuture.isSuccess()){
  10. channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
  11. }else{
  12. promise.setFailure(regFuture.cause());
  13. }
  14. }
  15. });
  16. }
除了监听端口还不够,还要处理IO事件:
  1. @Override
  2. protectedvoid run(){
  3. for(;;){
  4. boolean oldWakenUp = wakenUp.getAndSet(false);
  5. try{
  6. if(hasTasks()){
  7. selectNow();
  8. }else{
  9. select(oldWakenUp);
  10. // 'wakenUp.compareAndSet(false, true)' is always evaluated
  11. // before calling 'selector.wakeup()' to reduce the wake-up
  12. // overhead. (Selector.wakeup() is an expensive operation.)
  13. //
  14. // However, there is a race condition in this approach.
  15. // The race condition is triggered when 'wakenUp' is set to
  16. // true too early.
  17. //
  18. // 'wakenUp' is set to true too early if:
  19. // 1) Selector is waken up between 'wakenUp.set(false)' and
  20. // 'selector.select(...)'. (BAD)
  21. // 2) Selector is waken up between 'selector.select(...)' and
  22. // 'if (wakenUp.get()) { ... }'. (OK)
  23. //
  24. // In the first case, 'wakenUp' is set to true and the
  25. // following 'selector.select(...)' will wake up immediately.
  26. // Until 'wakenUp' is set to false again in the next round,
  27. // 'wakenUp.compareAndSet(false, true)' will fail, and therefore
  28. // any attempt to wake up the Selector will fail, too, causing
  29. // the following 'selector.select(...)' call to block
  30. // unnecessarily.
  31. //
  32. // To fix this problem, we wake up the selector again if wakenUp
  33. // is true immediately after selector.select(...).
  34. // It is inefficient in that it wakes up the selector for both
  35. // the first case (BAD - wake-up required) and the second case
  36. // (OK - no wake-up required).
  37. if(wakenUp.get()){
  38. selector.wakeup();
  39. }
  40. }
  41. cancelledKeys =0;
  42. needsToSelectAgain =false;
  43. finalint ioRatio =this.ioRatio;
  44. if(ioRatio ==100){
  45. processSelectedKeys();
  46. runAllTasks();
  47. }else{
  48. finallong ioStartTime =System.nanoTime();
  49. processSelectedKeys();
  50. finallong ioTime =System.nanoTime()- ioStartTime;
  51. runAllTasks(ioTime *(100- ioRatio)/ ioRatio);
  52. }
  53. if(isShuttingDown()){
  54. closeAll();
  55. if(confirmShutdown()){
  56. break;
  57. }
  58. }
  59. }catch(Throwable t){
  60. logger.warn("Unexpected exception in the selector loop.", t);
  61. // Prevent possible consecutive immediate failures that lead to
  62. // excessive CPU consumption.
  63. try{
  64. Thread.sleep(1000);
  65. }catch(InterruptedException e){
  66. // Ignore.
  67. }
  68. }
  69. }
  70. }
该方法是NioEventLoop
 
 
 
 
 

Netty服务端的业务流程分析的更多相关文章

  1. Netty服务端的启动源码分析

    ServerBootstrap的构造: public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, Serve ...

  2. Netty之旅三:Netty服务端启动源码分析,一梭子带走!

    Netty服务端启动流程源码分析 前记 哈喽,自从上篇<Netty之旅二:口口相传的高性能Netty到底是什么?>后,迟迟两周才开启今天的Netty源码系列.源码分析的第一篇文章,下一篇我 ...

  3. 【Netty源码分析】Netty服务端bind端口过程

    这一篇博客我们介绍一下Netty服务端绑定端口的过程,我们通过跟踪代码一直到NIO原生绑定端口的操作. 绑定端口操作 ChannelFuture future = serverBootstrap.bi ...

  4. Netty 服务端启动过程

    在 Netty 中创建 1 个 NioServerSocketChannel 在指定的端口监听客户端连接,这个过程主要有以下  个步骤: 创建 NioServerSocketChannel 初始化并注 ...

  5. Netty 服务端创建

    参考:http://blog.csdn.net/suifeng3051/article/details/28861883?utm_source=tuicool&utm_medium=refer ...

  6. netty服务端启动--ServerBootstrap源码解析

    netty服务端启动--ServerBootstrap源码解析 前面的第一篇文章中,我以spark中的netty客户端的创建为切入点,分析了netty的客户端引导类Bootstrap的参数设置以及启动 ...

  7. Netty服务端NioEventLoop启动及新连接接入处理

    一 Netty服务端NioEventLoop的启动 Netty服务端创建.初始化完成后,再向Selector上注册时,会将服务端Channel与NioEventLoop绑定,绑定之后,一方面会将服务端 ...

  8. Netty服务端Channel的创建与初始化

    Netty创建服务端Channel时,从服务端 ServerBootstrap 类的 bind 方法进入,下图是创建服务端Channel的函数调用链.在后续代码中通过反射的方式创建服务端Channel ...

  9. netty服务端客户端启动流程分析

    服务端启动流程 我们回顾前面讲解的netty启动流程,服务端这边有两个EventLoopGroup,一个专门用来处理连接,一个用来处理后续的io事件 服务端启动还是跟nio一样,绑定端口进行监听,我们 ...

随机推荐

  1. BZOJ - 2142 礼物 (扩展Lucas定理)

    扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正) 原理: https://blog.csdn.net/hqddm1253679098/article/details ...

  2. LeetCode 336. Palindrome Pairs

    原题链接在这里:https://leetcode.com/problems/palindrome-pairs/ 题目: Given a list of unique words, find all p ...

  3. Linux基础命令-系统时间

    Linux启动时从硬件读取日期和时间信息,读取完成以后,就不再与硬件相关联 Linux的两种时钟 系统时钟:由Linux内核通过CPU的工作频率进行的: date:显示系统时间 +%D +%F dat ...

  4. Spring MVC 项目示例

    Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架.Spring的web框架围绕DispatcherServlet设计, 作用是将请求分发到不同 ...

  5. 机器学习:评价分类结果(Precision - Recall 的平衡、P - R 曲线)

    一.Precision - Recall 的平衡 1)基础理论 调整阈值的大小,可以调节精准率和召回率的比重: 阈值:threshold,分类边界值,score > threshold 时分类为 ...

  6. du 命令 -目前的目录所占的磁盘空间

    Linux du命令也是查看使用空间的,但是与df命令不同的是Linux du命令是对文件和目录磁盘使用的空间的查看,还是和df命令有一些区别的. 1.命令格式: du [选项][文件] 2.命令功能 ...

  7. XXXAction-validation.xml文件中报错:Referenced file Contains errors

    我们需要引用与验证器配置相关的dtd文件,这个文件可以在xwork-core-2.3.1.2.jar下找到(xwork-validator-1.0.3.dtd) 网上有很多处理办法,如下所示: 1.直 ...

  8. Mongodb 3.6 副本集测试及添加删除节点等操作

    下载tar包并安装curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.6.8.tgz [root@mysqlt ...

  9. Maven的Snapshot版本与Release版本

    1. Snapshot版本代表不稳定.尚处于开发中的版本 2. Release版本则代表稳定的版本 3. 什么情况下该用SNAPSHOT? 协同开发时,如果A依赖构件B,由于B会更新,B应该使用SNA ...

  10. String是基本的数据类型吗?

    String不是基本的数据类型,是final修饰的java类,java中的基本类型一共有8个,它们分别为: 1 字符类型:byte,char 2 基本整型:short,int,long 3 浮点型:f ...