初识Netty——编解码技术、私有协议栈

TCP粘包/拆包问题

在业务上可能会存在一个完整的包被TCP拆分为多个包进行发送,也可能把多个小的包装封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题

图解:

解决方案:

  1. 消息定长,例如每个报文的大小为固定长度200字节,如果不够,空位补空格;
(2)在包尾增加回车换行符进行分割,例如FTP协议
(3)将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息体长月
的字段,通常设计思路为消息头的第一个字段使用 int32来表示消息的总长度;
(4)更复杂的应用层协议

利用Line based frameDecoder解决TCP粘包问题例子

Server端:

在handler之前增加了两个解码器

对比之前的string body:

Client端:

此时拿到的msg消息已经是解码成字符串后的应答消息了

也就是说,只需要将支持半包解码的handler添加到channelpipeline中即可

解码器原理分析:LineBasedFramcDecoder的工作原理是它依次遍历 ByteBuf 中的可读字节,判断看是
否有“\n”或者“\r\n”,如果有,就以此位置为结束位置,从可读索引到结束位置区间的
字节就组成了一行;stringDecoder的功能非常简单,就是将接收到的对象转换成字符串,然后继续调用后
面的Handler。LineBasedFrameDecoder+StringDecoder 组合就是按行切换的文本解码器,
它被设计用来支持TCP的粘包和拆包。

 分隔符和定长解码器的应用

DeimiterBasedFrameDecoder 应用开发:

通过对DelimiterBasedFrameDecoder的使用,我们可以自动完成以分隔符作为码流结束标识的消息的解码

FixedLengthFrameDecoder 应用开发
:

FixedLengthFrameDecoder 是固定长度解码器,它能够按照指定的长度对消息进行自动解码

还可以利用telnet进行测试,具体见书本

 解编码技术

Java对象可以通过序列化技术作为字节数组写入文件,可以上传网络

Java序列化的缺点:

无法跨语言、序列化后的码流太大、序列化性能太低

 私有协议栈开发

利用netty的NIO TCP协议来开发私有协议

所谓协议的开发,就是利用netty来对协议功能和一些模块进行规定

 一个netty节点可以作为服务端也可以作为客户端

协议栈功能描述:(1)基于Netty的NIO通信框架,提供高性能的异步通信能力;

  1. 提供消息的编解码框架,可以实现 POJO的序列化和反序列化;

(3)提供基于IP地址的白名单接入认证机制;

(4)链路的有效性校验机制;

(5)链路的断连重连机制。

协议应当具有上述功能

通信模型:

心跳检测机制:双方之间的心跳采用 Ping-Pong机制,当链路处于空闲状态时,客,户端主动发送Ping 消息给服务端,服务端接收到Ping 消息后发送应答消息Pong给客户端,如果客户端连续发送N条 Ping 消息都没有接收到服务端返回的Pong 消息,说明链路已经,挂死或者对方处于异常状态,客户端主动关闭连接,间隔周期 T后发起重连操作,直到重连成功。

消息定义:

Netty协议的编解码规范:

链路的建立:

客户端与服务端链路建立成功之后,由客户端发送握手请求消息,握手请求消息的定义如下:(1)消息头的 type 字段值为3;(2)可选附件为个数为0;(3)消息体为空;(4)握手消息的长度为22个字节。

服务端接收到客户端的握手请求消息之后,如果 IP 校验通过,返回握手成功应答息给客户端,应用层链路建立成功。握手应答消息定义如下。(1)消息头的 type 字段值为4:(2)可选附件个数为0;(3)消息体为byte类型的结果,“0”表示认证成功;“-1”表示认证失败。链路建立成功之后,客户端和服务端就可以互相发送业务消息了。

链路的关闭:

一般不需要主动关闭,但在如下情况下需要关闭:宕机重启、读写过程发生IO异常、心跳消息读写发生IO异常、心跳超时、编码异常

 协议可靠性设计:心跳机制重连机制(客户端发起重连操作,首次断联时客户端等待INTERVAL事件之后再发起重连)、重复登陆保护(在缓存的地址中查看客户端是否已经登录)、消息缓存重发(无论客户端还是服务端,当发生链路中断之后,在链路恢复之前,缓存在消息队列中,待发送的消息不能丢失,等链路恢复之后,重新发送这些消息,保证链路中断期间消息不丢失)

消息头header类定义:

消息编码类:

消息解码类:

握手和安全认证:

客户端部分

服务端握手接入和安全认证代码:

首先根据客户端的源地址(/127.0.0.1:12088)进行重复登录判断,如果客户端已经登录成功,拒绝重复登录,以防止由于客户端重复登录导致的句柄泄漏。随后通过 ChanneIHandlerContext 的Channel 接口获取客户端的 InetSocketAddress地址,从中取得发送方的源地址信息,通过源地址进行白名单校验,校验通过握手成功,否则握手失败。最后通过 buildResponse 构造握手应答消息返回给客户端

  • 15
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值