《Netty权威指南》笔记——Netty多协议开发和应用

  • 第12章 私有协议栈开发
    • 私有协议介绍
    • Netty协议栈功能设计
      • 网络拓扑图
      • 协议栈功能描述
      • 通信模型
      • 消息定义
        • 消息头
        • 消息体
      • Netty协议的编解码规范
        • 1. Netty协议编码
        • 2. Netty协议的解码
      • 链路的建立
      • 链路的关闭
      • 可靠性设计
      • 安全性设计
  • 第13章 服务端创建
    • Netty服务端创建源码分析
      • Netty服务端创建时序图
      • Netty服务端创建源码分析
  • 第14章 客户端创建
    • Netty客户端创建流程分析
    • Netty客户端创建源码分析
      • 客户端连接辅助类Bootstrap
      • 客户端连接操作

第12章 私有协议栈开发

私有协议介绍

私有协议具有封闭性, 垄断性,排他性的特点. Netty提供的异步TCP协议栈开发一个私有协议栈, 该协议栈被命名为Netty协议栈.

Netty协议栈功能设计

Netty协议栈用于内部各模块之间的通信, 基于TCP/IP协议栈, 一个类HTTP协议的应用层协议栈, 相比于传统的标准协议栈, 它更加轻巧,灵活和实用

网络拓扑图

Netty节点没有服务端和客户端的区分, 谁首先发起连接, 就作为客户端, 另一方自然成为服务端. 一个Netty节点既可以作为客户端连接另外的Netty节点, 也可以作为Netty服务端被其他Netty节点连接.

协议栈功能描述

  1. 基于Netty的NIo通信框架, 提供高性能的异步通信能力
  2. 提供消息的编解码框架, 可以实现POJO的序列化和反序列化
  3. 提供基于IP地址的白敏弹接入认证机制
  4. 链路的有效性校验机制
  5. 链路的断连重连机制

通信模型

消息定义

由两个部分组成:

消息头

消息体

Netty协议的编解码规范

1. Netty协议编码

ercCode,length,sessionID, type, Priority:
put()默认byte输入, 其他类型用特定put, e.g. putInt() , putLong()

attachment:

  1. 首先对附件个数进行编码
  2. 然后对Key进行编码
    1. 长度
    2. 再转换成byte数组之后编码的内容

body:
通过JBoss Marshalling 序列化为Byte数组, 然后调用java.nio.ByteBuffer.put(byte [] src) 将其写入ByteBuffer缓冲区中.

2. Netty协议的解码

ercCode,length,sessionID, type, Priority:
get()默认byte输入, 其他类型用特定get, e.g. getInt() , getLong()

attachment:
创建一个新的attachment对象, 调用java.nio.ByteBuffer.getInt()获取附件的长度

  • 如果长度0, 结束解码
  • 如果长度不为0, 解码消息体, 如果非空, 根据擦和高难度通过for循环进行解码

body:
通过JBoss marshaller解码

链路的建立

链路建立需要通过基于IP地址或者号段的黑白名单安全认证机制.
作为样例, 本协议使用基于IP地址的安全认证, 如果有多个IP, 通过逗号进行分割. 在实际商用项目中, 安全认证机制会更加严格, 例如通过密钥对用户名和密码进行安全认证

  1. 客户端与服务器链路建立成功之后, 由客户端发送握手请求消息, 握手请求消息的定义如下

    1. 消息头的type字段值为3
    2. 可选附件个数为0
    3. 消息体为空
    4. 握手消息长度为22个字节
  2. 服务端接收到客户端的握手请求消息之后, 如果IP校验通过, 返回成功应答消息给客户端, 应用链路建立成功. 握手应答消息定义:

    1. 消息头的type字段值为4
    2. 可选附件个数为0
    3. 消息体为byte类型的结果
      1. “0” 表示认证成功
      2. “-1” 表示认证失败

链路的关闭

由于采用长连接通信, 在正常的业务运行期间, 双方通过心跳和业务消息维持链路, 任何一方都不需要主动关闭连接

除非出现以下情况

  1. 当对方宕机或者重启, 会主动关闭链路, 另一方读取到操作系统的通知信号, 得知对方REST链路, 需要关闭连接, 释放自身的句柄等资源. 由于采用TCP全双工通信, 通信双发都需要关闭连接, 释放资源
  2. 消息读写过程中, 发生了I/O异常, 需要主动关闭连接
  3. 心跳消息读写过程中发生了I/O异常, 需要主动关闭连接
  4. 心跳超时, 需要主动关闭连接
  5. 发生编码异常等不可恢复错误时, 需要主动关闭连接

可靠性设计

在恶劣的网络环境中, 例如网络超时,闪断, 对方进程僵死或者处理缓慢, 需要有可靠性设计

  1. 心跳机制

在业务低谷期, 如果发生闪断,等网络问题, 因为没有业务消息所以没有办法被监视, 到了业务高峰期会出现大量的网络通信失败. 心跳机制设计出来用来检测链路的互通性, 一旦发现网络故障, 立即关闭链路, 重连.

T: 连续的一个周期没有收到读写消息

设计思路:

  1. 当处于空闲状态时间达到 T. 客户端主动发送Ping心跳消息到服务端

  2. 如果下一个周期T到来, 客户端没有收到对方发送的Pong心跳应答消息或者读取到服务端发送的其他业务消息, 则心跳失败计数器+1

  3. 每当客户端接收到服务的业务消息或者Pong应答消息时, 将心跳失败计数器清零;

    连续N次没有接收到服务端的Pong消息或者业务消息, 则关闭链路, 间隔INTERVAL时间后发起重连操作

  4. 服务器网络空闲状态持续时间达到T后, 服务端将心跳失败计数器+1;

    只要接收到客户端发送的Ping消息或者其他业务消息, 计数器清零

  5. 服务端连续N次没有接收到客户端的Ping消息或者其他业务消息, 则关闭链路, 释放资源, 等待客户端重连

ping-pong 双向心跳机制, 保证无论通信哪一方出现网络故障, 都能被及时地检测出来. 为了防止由于对方段时间内繁忙没有及时返回应答造成的误判, 只有连续N次心跳检测都失败才认定链路损害, 需要关闭链路并重建链路

当读或者些心跳消息发生I/O异常的时候, 说明链路已经中断, 此时需要立即关闭链路, 客户端需要重新发起连接. 服务端需要清空缓存的宝宝消息, 等待客户端重连.

  1. 重连机制

如果链路中断, 等待INTERVAL时间后, 有客户端发起重连操作, 如果重连失败, 间隔周期INTERVAL后再次发起重连, 直到重连成功.

为了保证服务端能够有充足的时间释放句柄资源, 在首次断连时客户端需要等待INTERAVAL时间之后再发起重连, 而不是失败后就立即重连

为了保证句柄资源能够及时释放, 无论什么场景下的重连失败, 客户端都必须保证自身的资源被及时释放, 包括但不限于SocketChannel, socket等

重连失败后, 会打印ExceptionStackTrace 方便问题定位

  1. 重复登录保护

当客户端握手成功之后, 在链路处于正常状态下, 不允许客户端重复登录, 以防止客户端在异常状态下反复重连导致句柄资源被耗尽

服务端接收到客户端的握手请求信息之后, 首先检查IP是否合法, 如果校验成功, 在缓存的地址表中查看客户端是否已经登录, 如果已经登录, 则拒绝并返回错误码-1, 同时关闭TCP, 原因打印到日志.

客户端接收到失败的应答消息之后, 关闭客户端TCP连接, 等待INTERVAL时间, 再次发起TCP连接, 直到成功

  1. 消息缓存重发

无论客户端还是服务端, 当发生链路中断之后, 在链路恢复之前, 缓存在消息队列中待发送的消息不能丢失, 等链路恢复之后, 重新发送这些消息, 保证链路中断期间消息不丢失.

考虑到内存溢出的风险, 可以将消息缓存队列设置上限, 达到后可以拒绝队列 enqueue

安全性设计

内部长连接采用基于IP地址的安全认证机制, 服务端会对IP地址进行合法性校验, 并设置白名单
假如在公网中使用Netty, 会采用更严格的安全认证机制, 例如密钥和AES加密的用户名+密码认证机制, 也可以采用SSL/TSL安全传输

第13章 服务端创建

Netty服务端创建源码分析

Netty服务端创建时序图

ServerBootstrap是Socket服务端的启动辅助类, 用户通过Server Bootstrap 可以方便地创建Netty的服务端

  1. 创建ServerBootstrap实例

    ServerBootstrap因为它的参数太多了, 只有一个无参构造函数, 并且使用Builder模式.

  2. 设置并绑定Reactor线程池

    EventLoop处理所有注册到本线程多路复用器Selector上的Channel, Selector的轮训操作由绑定的EventLoop线程run方式驱动. 不仅仅是I/O, 用户自定义的Task和定时任务Task也同意由EventLoop负责.

  3. 设置并绑定服务端Channel
    需要创建ServerSocketChannel. Netty的Serverbootstrap方法提供了Channel方法用于制定服务端Channel的类型. Netty通过工厂类, 利用反射创建NioServerSocketChannel对象.

  4. 链路建立的时候创建并出示化ChannelPipeline
    并不是必需的. 是一个负责处理网络事件的职责链, 负责管理和执行ChannelHandler

  5. 初始化ChannelPipeline完成后, 添加并设置ChannelHandler
    ChannelHandler是Netty提供给用户定制和扩展的关键接口. 可以用ChannelHandler来实现: 消息编解码,心跳, 安全认证, TSL/SSL认证, 流量控制和流量整形等

  6. 绑定并启动监听端口, 在绑定监听端口之前系统会做一系列的初始化和检测工作, 完成之后, 会启动监听端口, 并将ServerSocketChannel注册到Selector上监听客户端连接

  7. Selector 轮询 由Reactor线程 NioEventLoop负责调度和执行Selector轮训操作, 选者准备就绪的Channel集合

  8. 当轮询到准备就绪的Channel之后, 就由Reactor 线程NioEventLoop执行ChannelPipeline的相应方法, 最终调度并执行ChannelHandler

  9. 执行Netty系统ChannelHandler和用户添加定制ChannelHandler. ChannelPipeline根据网络事件的类型, 调度并执行Channel Handler

Netty服务端创建源码分析

指定NioServerSocketChannel后, 需要设置TCP的backlog参数.

**backlog. **指定了内核为此套接口排队的最大连接个数,

对于给定的监听接口, 内核维护两个队列

  1. 未连接队列
  2. 已连接队列

根据TCP三路握手过程中三个分节来分隔这两个队列. 服务器处于listen状态, 收到客户端syn分节connect时在未完成队列中创建一个新的条目, 然后用三路握手的第二个分解即服务器的syn响应客户端, 此条目在第三个分解到达前(客户端对服务器syn的ack)一直保留在未完成连接队列中, 如果三路握手完成, 该条目将从未完成丽娜姐队列半岛已完成连接队列尾部. 当进程调用accept时,从已完成队列中的头部去除一个条目给进程, 当已完成队列为空时进程将睡眠, 直到有条目在已完成连接队列中才唤醒.


第14章 客户端创建

相比起服务端, Netty客户端的创建更加复杂, 除了要考虑线程模型、异步连接、客户端连接超时等因素外, 还需要考虑连接过程中的各种异常.

Netty客户端创建流程分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6n5zEpEd-1629290809051)(/Users/ruixi/Library/Application Support/typora-user-images/image-20210723134525797.png)]

  1. 用户线程创建Bootstrap实例, 通过API设置创建客户端相关的参数, 异步发起客户端连接
  2. 创建处理客户端连接, I/O读写的Reactor线程组NioEventLoopGroup, 可以通过构造函数指定I/O线程的个数, 默认为CPU内核数的2倍
  3. 通过Bootstrap的ChannelFactory的用户指定的Channel类型创建用于客户端连接的NioSocketChannel, 功能类似于JDK NIO类库提供的SocketChannel
  4. 创建默认的ChannelHandlerPipeline, 用于调度和执行网络事件
  5. 异步发起TCP连接, 判断连接是否成功. 如果成功, 则直接将NioSocketChannel注册到多路复用器上, 监听读操作位. 用于数据报读取和消息发送; 如果没有立即连接成功, 则注册链接监听位到多路复用器, 等待连接结果.
  6. 注册对应的网络监听状态位到多路复用器
  7. 由多路复用器在I/O现场中轮询各channel, 处理连接结果
  8. 如果连接成功, 设置Future结果, 发送连接成功事件触发ChannelPipeline执行
  9. 由ChannelPipeline调度执行系统的用户的ChannelHandler, 执行业务逻辑

Netty客户端创建源码分析

客户端连接辅助类Bootstrap

Netty Bootstrap提供的主要TCP参数

  • SO_TIMEOUT: 控制读取操作将阻塞多少毫秒

  • SO_SNDFBUF: 套接字发送缓冲区大小

  • SO_RCVBUF: 套接字使用的接收缓冲区大小

  • SO_REUSEADDR: 用于决定如果网络上仍然有数据相久的ServerSocket传输数据, 是否允许心的ServerSocket绑定到与旧的ServerSocket同样的端口上. 这个默认值跟操作系统有关, 在某些操作系统中,允许重用端口, 而在某些操作系统中不允许重用端口.

  • CONNECT_TIMEOUT_MILIS: 连接超时时间

  • TCP_NODELAY: 激活或者禁止TCP_NODELAY 套接字选项, 它决定是否使用Nagle算法.

channel接口: 用于指定客户端使用的channel接口, 对于TCP客户端连接, 默认使用NioSocket Channel

BooStrapChannelFactory利用channelClass类型信息, 通过反射机制创建NioSocketChannel对象

设置Handler接口: Bootstrap为了简化Handler的编排, 提供了ChannelInitializer, 它继承了ChannelHandlerAdapter, 当TCP链路注册成功之后, 调用initChannel接口, 用于设置用户ChannelHandler

客户端连接操作

  1. 创建和初始化NioSocketChannel
final ChannelFuture regFuture = initAndRegister();
  1. 从NioEventLoopGroup中获取NioEventLoop, 然后使用其作为参数创建NioSocketChannel
return channelFactory(). newChannel(eventLoop);
  1. 初始化Channel之后, 将其注册到Selector上,
channel.eventLoop().execute(new Runnable()){@Overridepublic void run(){if(regFuture.isSuccess()){if (localAddress == null){channel.connect(remoteAddress, promise);}else{channel.connect(remoteAddress,localAddressm,promise);}}}
}

《Netty权威指南》笔记 —— 第十二、十三、十四章相关推荐

  1. netty权威指南笔记-以回车换行结尾的消息如何处理半包问题

    概述 TCP底层会发生粘包和拆包,这个是TCP的一个特性.为了减少网络数据传输的次数,TCP总是希望让网络数据到达一定量级的时候才将数据发送出去,而不是缓存区一有数据就马上发送数据. TCP底层会根据 ...

  2. 《Netty权威指南》笔记 —— 第二十、二十一、二十二, 二十三章

    <Netty权威指南>笔记--Netty高级特性 第20章 Netty架构剖析 Reactor通信调度层 职责链 ChannelPipeline 业务逻辑编排层 关键架构质量属性 高性能 ...

  3. 《Netty权威指南 第2版》学习笔记(1)---服务端与客户端开发入门

    前言 Netty权威指南中以时间服务器为入门案例,演示了如何通过Netty完成了服务端与客户端之间的交互过程. 在开始使用Netty开发之前,先回顾一下使用NIO进行服务端开发的步骤. 创建Serve ...

  4. netty权威指南 学习笔记http

    序 李林峰的<netty权威指南>,从Java的NIO开始介绍,后面介绍TCP粘包拆包.中级篇介绍编解码技术. 第10章介绍了HTTP及netty HTTP+XML的技术. 因为xml实际 ...

  5. Netty权威指南(四)TCP粘包/拆包问题

    TCP粘包/拆包问题解决之道 上一章 一.介绍 1.1 TCP粘包/拆包问题说明 1.2 TCP粘包/拆包发生的原因 1.3 粘包问题的解决策略 二.未考虑TCP粘包导致的功能异常案例 2.1 Tim ...

  6. 《Netty权威指南》

    <Netty权威指南> 基本信息 作者: 李林锋 出版社:电子工业出版社 ISBN:9787121233432 上架时间:2014-5-29 出版日期:2014 年6月 开本:16开 页码 ...

  7. HTML5与CSS3权威指南笔记案例1

    第1章 <!DOCTYPE html> <meta charset = "UTF-8"> <title> Search </title&g ...

  8. [201504][Netty 权威指南][第2版][李林锋][著]

    [201504][Netty 权威指南][第2版][李林锋][著] https://github.com/wuyinxian124/nettybook2 基础篇 走进 Java NIO 第 1 章 J ...

  9. IT人物之《Netty权威指南》中文作者 专访华为李林锋:我与Netty那些不得不说的事

    摘要:Netty是业界最流行的NIO框架之一,它的健壮性.功能.性能.可定制性和可扩展性在同类框架中都是首屈一指的.近日,CSDN采访了Netty领域的权威人士李林锋,请他分享Netty开发的经验之道 ...

  10. 我在千峰培训的日子第十二–十三天------面向对象【继承】

    我在千峰培训的日子第十二–十三天------面向对象[继承] 今日感悟 人生最遗憾的莫过于放弃了不该放弃的,固执的坚持了不该坚持的. 老师知识点 一.局部变量跟成员变量 形参和实参 形参:定义在方法中 ...

最新文章

  1. Redis+分布式+设计模式+Spring全家桶+Dubbo阿里P8技术精选文档
  2. 11.swift 单例
  3. VTK:相互作用之MouseEvents
  4. 项目 我行我素购物管理系统 0913
  5. call需要多大带宽 video_KCP TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的是充分利用带宽。而KCP是为流速设计的(单个数据包从一端发送到一端需要多少时间)...
  6. (匹配)Fire Net --hdu --1045
  7. oracle sql中打印,在Oracle SQL Developer SQL工作表窗口中打印文本
  8. Memcached在Windows7上的安装问题
  9. 页面body元素#65279导致顶部空白一行解决方法
  10. 位置度标注方法图解_追踪主力-散户操盘实战图解:操盘手法分析
  11. golang GUI编程之walk初建
  12. rostcm6情感分析案例分析_案例分析,小刘如何处理情感关系?
  13. windows系统mysql常用命令_Windows下 MySQL命令 常用操作
  14. IDEA打包jar包详尽流程
  15. 2019下半年计算机二级c语言,2019年下半年计算机二级C语言试题(4)
  16. python colormap函数_Python colormap库的安装和使用详情
  17. java sequencer_UVM学习笔记--sequence和sequencer(转)
  18. java web 下拉列表_web中下拉列表的几种实现
  19. SPIN Routing Algorithm
  20. 机械硬盘显示容量0字节要如何办啊

热门文章

  1. 开宗明义—UEFI介绍 (一)
  2. 为什么图灵奖获得者戴克斯特拉痛恨 BASIC 语言
  3. 村村响农村广播-盐池县农村IP广播案例
  4. 多开 android模拟器,安卓模拟器如何多开窗口保证游戏不封号
  5. oracle 获取月份_网络工程师干货 | 2020年7月份最新的华为HCIARS培训教程,画质超级好!...
  6. java js页面提示报警声音
  7. sourcesafe的七个问题?
  8. linux嵌入式聊天室的程序,基于Linux网络聊天室的设计与实现
  9. flv格式怎么转换成mp4
  10. 学刘红杰老师博客营销,知如何提高博客访问流量