Netty中粘包和半包产生原因有哪些

Netty中粘包和半包产生原因有哪些

这篇文章主要介绍了Netty中粘包和半包产生原因有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

定义

TCP 传输中,客户端发送数据,实际是把数据写入到了 TCP 的缓存中,粘包和半包也就会在此时产生。

Netty中粘包和半包产生原因有哪些

客户端给服务端发送了两条消息ABCDEF,服务端这边的接收会有多少种情况呢?有可能是一次性收到了所有的消息ABCDEF,有可能是收到了三条消息ABCDEF

上面所说的一次性收到了所有的消息ABCDEF,类似于粘包。如果客户端发送的包的大小比 TCP 的缓存容量小,并且 TCP 缓存可以存放多个包,那么客户端和服务端的一次通信就可能传递了多个包,这时候服务端从 TCP 缓存就可能一下读取了多个包,这种现象就叫粘包

上面说的后面那种收到了三条消息ABCDEF,类似于半包。如果客户端发送的包的大小比 TCP 的缓存容量大,那么这个数据包就会被分成多个包,通过 Socket 多次发送到服务端,服务端第一次从接受缓存里面获取的数据,实际是整个包的一部分,这时候就产生了半包(半包不是说只收到了全包的一半,是说收到了全包的一部分)。

产生原因

其实从上面的定义,我们就可以大概知道产生的原因了。

粘包的主要原因:

  1. 发送方每次写入数据 < 套接字(Socket)缓冲区大小

  2. 接收方读取套接字(Socket)缓冲区数据不够及时

半包的主要原因:

  1. 发送方每次写入数据 > 套接字(Socket)缓冲区大小

  2. 发送的数据大于协议的 MTU (Maximum Transmission Unit,最大传输单元),因此必须拆包

其实我们可以换个角度看待问题:

  1. 收发的角度看,便是一个发送可能被多次接收,多个发送可能被一次接收。

  2. 传输的角度看,便是一个发送可能占用多个传输包,多个发送可能共用一个传输包。

根本原因,其实是

TCP 是流式协议,消息无边界。

(PS :UDP 虽然也可以一次传输多个包或者多次传输一个包,但每个消息都是有边界的,因此不会有粘包和半包问题。)

解决方法

就像上面说的,UDP 之所以不会产生粘包和半包问题,主要是因为消息有边界,因此,我们也可以采取类似的思路。

改成短连接

将 TCP 连接改成短连接,一个请求一个短连接。这样的话,建立连接到释放连接之间的消息即为传输的信息,消息也就产生了边界。

这样的方法就是十分简单,不需要在我们的应用中做过多修改。但缺点也就很明显了,效率低下,TCP 连接和断开都会涉及三次握手以及四次握手,每个消息都会涉及这些过程,十分浪费性能。

因此,并不推介这种方式。

封装成帧

封装成帧(Framing),也就是原本发送消息的单位是缓冲大小,现在换成了帧,这样我们就可以自定义边界了。一般有4种方式:

固定长度

这种方式下,消息边界也就是固定长度即可。

优点就是实现很简单,缺点就是空间有极大的浪费,如果传递的消息中大部分都比较短,这样就会有很多空间是浪费的。

因此,这种方式一般也是不推介的。

分隔符

这种方式下,消息边界也就是分隔符本身。

优点是空间不再浪费,实现也比较简单。缺点是当内容本身出现分割符时需要转义,所以无论是发送还是接受,都需要进行整个内容的扫描。

因此,这种方式效率也不是很高,但可以尝试使用。

专门的 length 字段

这种方式,就有点类似 Http 请求中的 Content-Length,有一个专门的字段存储消息的长度。作为服务端,接受消息时,先解析固定长度的字段(length字段)获取消息总长度,然后读取后续内容。

优点是精确定位用户数据,内容也不用转义。缺点是长度理论上有限制,需要提前限制可能的最大长度从而定义长度占用字节数。

因此,十分推介用这种方式。

其他方式

其他方式就各不相同了,比如 JSON 可以看成是使用{}是否成对。这些优缺点就需要大家在各自的场景中进行衡量了。

Netty 中的实现

Netty 支持上文所讲的封装成帧(Framing)中的前三种方式,简单介绍下:

方式解码编码
固定长度FixedLengthFrameDecoder简单
分割符DelimiterBasedFrameDecoder简单
专门的 length 字段LengthFieldBasedFrameDecoderLengthFieldPrepender

感谢你能够认真阅读完这篇文章,希望小编分享的“Netty中粘包和半包产生原因有哪些”这篇文章对大家有帮助,同时也希望大家多多支持恰卡编程网,关注恰卡编程网行业资讯频道,更多相关知识等着你来学习!

发布于 2021-12-28 22:17:52
收藏
分享
海报
0 条评论
53
上一篇:Netty对底层Selector如何优化 下一篇:Netty中线程名称的示例分析
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码