首页 > 其他分享 >《netty实战》笔记 1-8章

《netty实战》笔记 1-8章

时间:2023-03-02 10:55:06浏览次数:44  
标签:实战 netty ChannelHandler bootstrap 笔记 Handler 客户端 方法 ChannelOption

第1章

 

 

 

 

 

 

 

 

 

 

 

 

此方式(java API阻塞方式):一个客户端——一个线程

当客户端连接非常多时很不理想   Java NIO——非阻塞

 

 

 

 

 

 

 

 

 回调就是ChannelHandler的方法(一个Handler包含多个回调)

事件是 按照它们与入站或出站数据流的相关性进行分类的。即网络事件 连接激活或连接失活 数据读取 用户事件 错误事件   打开或关闭到远程节点的连接 将数据写到或者冲刷到套接字 注册,绑定,写入,写入并冲刷等操作后都有返回ChannelFuture Bootstrap方法(绑定或连接成功后netty执行自己定义的Listener回调方法)和ChannelOutboundInvoker方法(ChannelInitializer自己实现方法initChannel 先后注册Handler到pipeline,netty自动根据顺序处理这些Handler,Handler调用这些自己实现的回调方法)

 

 

 

 

 

 

 一个回调其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用,多种事件有多种回调【如建立连接,断开连接】

 

 

 Channel 类型——EpollServerSocketChannel(Linux) 或 NioServerSocketChannel

 

 

 

 

 

 

 

 

 连接回调后:Future添加Listener处理连接的多种情况(连接成功,发生错误等),即Future是回调的精细化处理。

 

 

 第2章 你的第一款netty应用程序

********************************第2章 客户端和服务端主要两个东西 1ChannelHandler逻辑 2EventLoop引导

 

 EventLoop:顾名思义 事件循环

EventLoop中有一个死循环的run方法,每时每刻都在检查绑定在自己身上的socket是否有事件发生,并处理这些事件;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 一个ChannelPipeline有一个ChannelHandler实例链,即:一个Channel有一个ChannelHandler实例链(ChannelHandler集合)

 

 

 

 

 

 

 

 

 

 

 

 引导ServerBootstrap

 

 

 

 

 

 

 

 

 

 

 

 

/**
 * 启动函数,地址和端口号
 */
public boolean start(String address, int port, ChannelHandler handler) {
   boolean isEpoll = Epoll.isAvailable();
   int cpuNum = Runtime.getRuntime().availableProcessors();

   if (isEpoll) {
      bossGroup = new EpollEventLoopGroup(cpuNum);
      workGroup = new EpollEventLoopGroup(cpuNum * 2 + 1);
   } else {
      bossGroup = new NioEventLoopGroup(cpuNum);
      workGroup = new NioEventLoopGroup(cpuNum * 2 + 1);
   }
   try {
      ServerBootstrap bootstrap = new ServerBootstrap();
      bootstrap.group(bossGroup, workGroup);
      bootstrap.channel(isEpoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class);
      bootstrap.handler(new LoggingHandler(LogLevel.INFO));
      bootstrap.childHandler(handler);

      // TIME_WAIT时可重用端口,服务器关闭后可立即重启,此时任何非期
      // 望数据到达,都可能导致服务程序反应混乱,不过这只是一种可能,事实上很不可能
      bootstrap.option(ChannelOption.SO_REUSEADDR, true);
      // 设置了ServerSocket类的SO_RCVBUF选项,就相当于设置了Socket对象的接收缓冲区大小,4KB
      bootstrap.option(ChannelOption.SO_RCVBUF, 1024 * 8);
      // 请求连接的最大队列长度,如果backlog参数的值大于操作系统限定的队列的最大长度,那么backlog参数无效
      bootstrap.option(ChannelOption.SO_BACKLOG, 1024);

      // 使用内存池的缓冲区重用机制
      bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

      // 当客户端发生断网或断电等非正常断开的现象,如果服务器没有设置SO_KEEPALIVE选项,则会一直不关闭SOCKET。具体的时间由OS配置
      bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
      // 在调用close方法后,将阻塞n秒,让未完成发送的数据尽量发出,netty中这部分操作调用方法异步进行。我们的游戏业务没有这种需要,所以设置为0
      bootstrap.childOption(ChannelOption.SO_LINGER, 0);
      // 数据包不缓冲,立即发出
      bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
      // 发送缓冲大小,默认8192
      bootstrap.childOption(ChannelOption.SO_SNDBUF, 1024 * 8);
      // 使用内存池的缓冲区重用机制
      bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

      bootstrap.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 64, 1024 * 128));

      channelFuture = bootstrap.bind(new InetSocketAddress(address, port));
      channelFuture.sync();//阻塞,知道绑定操作完成为止

      Log.info("NettyComponentSocket->start, service start success address:{} port:{} isEpoll:{}", address, port, isEpoll);
      return true;
   } catch (Exception e) {
      Log.error("NettyComponent->start, init netty exception, address:{} port:{}", address, port, e);
      return false;
   }
}

 

 

 

 

 

 

 

 

 最大的区别在于SimpleChannelInboundHandler会对没有外界引用的资源进行一定的清理,并且入站的消息可以通过泛型来规定。

ChannelInboundHandlerAdapter是ChannelInboundHandler一个简单实现,默认情况下不会做任何处理。只是简单的将操作通过fire方法传到ChannelPipeline中的下一个ChannelHandler中让链中的下一个ChannelHandler去处理。但是需要注意的是信息经过channelRead方法处理之后不会自动释放(是因为信息不会被自动释放所以能将信息传给下一个ChannelHandler处理。其次,在实现类Handler中,你仍然需要将传入消息回送给发送者,而 write() 操作是异步的,直到 channelRead() 方法返回后可能仍然没有完成。为此,实现类Handler扩展了 ChannelInboundHandlerAdapter ,其在这个时间点上不会释放消息。)     SimpleChannelInboundHandler支持泛型的消息处理,默认情况下消息处理完之后将会自动释放,无法提供fire*方法传递给ChannelPipeline中的下一个ChannelHandler.在客户端,当 channelRead0() 方法完成时,你已经有了传入消息,并且已经处理完它了。当该方法返回时,SimpleChannelInboundHandler负责释放指向保存该消息的ByteBuf的内存引用(自动调用Bytebuffer.release())。而为何服务器端不能用呢,因为我们想让服务器把客户端请求的数据发送回去,而服务器端有可能在channelRead方法返回前还没有写完数据,因此不能让它自动release。  

 

项目中服务端也用了,有点奇怪?——可能是s2s用到。

 

 引导Bootstrap,服务端是local,客户端是remoteAddress

 

 

 

 

 

 

 

 第3章 Netty的组件和设计

********************************第3章 Netty的组件和设计  

引导——网络层配置容器

 

 

 

 

 

 

 

 

 

 一个线程——一个selector(注册表作用) —— 多个客户端——多个Channel

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 服务端两组Channel(EventLoopGroup),一组管理服务端ServerChannel,一组管理传入的客户端连接的Channel。

 

 第4章 传输

 

 

 

 

 

 

 

 每个Channel都将会分配一个ChannelPipeline和ChannelConfig

 

 拦截过滤器——执行一遍注册的拦截器(Handler方法)

  1、先基于长度的解码器LengthFieldBasedFrameDecoder【继承自ByteToMessageDecoder】 (2 3)、服务端多两个Handler(心跳监测IdleStateHandler,心跳日志处理ChannelInboundHandlerAdapter) 2、再编解码器CombinedChannelDuplexHandler 的容器。 3、最后是接收处理消息的Handler

 

 

 基于长度的解码器LengthFieldBasedFrameDecoder【继承自ByteToMessageDecoder】:

读取到的数据是基于流的, 而且是有方向的. 然而数据是没有边界的, 不知道从哪儿到哪儿是一个完整的数据, 下一个数据又是从哪个到哪个. 因此应用层需要设定规则, 根据规则就可以知道数据的边界在哪儿. 如何根据规则知道数据边界:规则一般是什么样的

 

 

 如上图, 便是根据设定的规则, 就可以’筛选’出来真正有意义的数据(data)在哪个. 而且允许每个data的长度是不一样大小.

  那么就要说下这个规则是什么了. 规则是由4个主要的属性构成, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip. 通过一个数据块为例介绍这4个属性.

 

 

如上图, 从红色箭头指向的位置开始读取数据. lengthFieldOffset表示长度字段的偏移量, 经过lengthFieldOffset之后, 箭头指向了下一个位置. 如果lengthFieldOffset=3, 那么箭头需要向右边走3个字节.

 

 

 

 

 

 

 

 

 

 

 

 

 零拷贝特性。nio和 epoll类型传输时才可使用。ByteBuf内置的复合缓冲区类型 零拷贝。

 

 

 

 

 

 

 第 5 章 ByteBuf

 

 

 

 

 

 

 slice:片,切片

 

 尽量使用slice替换copy方法,减少复制开销,但是要注意 共享数据问题。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 第 6 章 ChannelHandler 和 ChannelPipeline

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ChannelHandlerContext的高级用法。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 第 7 章 EventLoop 和 线程模型

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 第8章 引导

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:实战,netty,ChannelHandler,bootstrap,笔记,Handler,客户端,方法,ChannelOption
From: https://www.cnblogs.com/erlongxizhu-03/p/17171048.html

相关文章

  • 论文阅读笔记(四):AS-MLP AN AXIAL SHIFTED MLP ARCHITECTUREFOR VISION
    1.摘要本文提出了一种轴向移位的MLP体系结构(AS-MLP),更关注局部特征的交互,通过特征图的通道轴移动,AS-MLP能够从不同的轴获取信息,这使得网络能够捕捉局部依赖(可以理解为cn......
  • 组合数学笔记-特殊计数数列
    目录特殊计数数列斐波那契数列斐波那契数列的定义与基本性质卡特兰数卡特兰数的定义与基本性质卡特兰数的应用满足通项关系的情况满足递推关系的情况斯特林数贝尔数分拆数......
  • PyQt5 自然语言处理学习笔记(一)
    前言最近想将自然语言处理的项目进行可视化,尽量还是使用回Python语言,因此打算用PyQT来实现相应的功能。入门案例一个简单的自然语言处理的demo,使用PyQt框架,该demo可以读......
  • C++ STL学习笔记-C++ STL基础
    仅自己回忆使用,若有侵权,联系删除algorithm实用库函数sort:迭代器类型必须为随机访问迭代器(first,last),应该支持<运算符,可以自己写比较nth_element()>partial_sort()......
  • CF1799 解题笔记
    A模拟即可。#include<bits/stdc++.h>#defineILinline#defineregregister#defineN50050ILintread(){regintx=0;regcharch=getchar();while(c......
  • Binary GCD 学习笔记
    算是一点杂项吧,感觉没什么机会用上。0x00前言有时你需要大量且快速的求gcd,像P5435。但是对值域预处理gcd又很麻烦,所以这时候我们可以考虑BinaryGCD。0x01原理......
  • TJA1020应用笔记(AN00093)
    1. itisdissuadedtoconnectNSLPdirectlytoaVCCsupplysource.NSLP最好不要与VCC直接连接。 2.(NLSPpin)Therangeoftheinputthresholdis chosento......
  • 扩展欧几里得学习笔记
    温馨提示:本文推式子比较多,建议跟着文章自己推一推。扩展欧几里得是什么扩展欧几里得(exgcd)是一个可以用来求\(ax+by=c\)(\(c\%\gcd(a,b)=0\),否则无解)的解的算法求解\(ax......
  • 均值不等式学习笔记
    从平均数说起我们都知道\(n\)个数的平均数表示为:\[\frac{a_1+a_2+a_3+\cdotsa_n}{n}\]这种最常见的平均数被称为“算术平均数”(ArithmeticMean)。还有一种常用的平均......
  • mysql牛客网实战练习
    1、模糊查询字段名like'匹配内容'_:下划线代表匹配任意一个字符;%:百分号代表匹配0个或多个字符;[]:中括号代表匹配其中的任意一个字符;[^]:^尖冒号代表......