您当前的位置:首页 > 电脑百科 > 网络技术 > 网络知识

TCP粘拆包详解与Netty代码示例

时间:2019-08-28 11:42:24  来源:  作者:

TCP是个“流”协议,所谓流,就是没有界限的一串数据。可以想想河里的流水,是连成一片的,其间并没有分界线。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

有关TCP的详细讲解,可以点击关于三次握手与四次挥手你要知道这些和快速了解TCP的流量控制与拥塞控制

TCP粘包或拆包的原因

  1. 应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。
  2. 应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包。
  3. 进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发生拆包。
  4. 接收方法不及时读取套接字缓冲区数据,这将发生粘包。

拆包和粘包的形式

第一种情况:接收端正常收到两个数据包,即没有发生拆包和粘包的现象,此种情况不在本文的讨论范围内。

 

TCP粘拆包详解与Netty代码示例

 

 

发生拆包

第二种情况:接收端只收到一个数据包,由于TCP是不会出现丢包的,所以这一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包。这种情况由于接收端不知道这两个数据包的界限,所以对于接收端来说很难处理。

 

TCP粘拆包详解与Netty代码示例

 

 

发生粘包

第三种情况:这种情况有两种表现形式,如下图。接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包。这两种情况如果不加特殊处理,对于接收端同样是不好处理的。

 

TCP粘拆包详解与Netty代码示例

 

 

发生拆包和粘包

TCP粘拆包详解与Netty代码示例

 

 

发生拆包和粘包

粘包和拆包的解决办法

  1. 发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
  2. 发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
  3. 可以在数据包之间设置边界,添加特殊符号(如:回车符),这样,接收端通过这个边界就可以将不同的数据包拆分开。

Netty中的代码示例

Netty封装了JDK的NIO,是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能服务器和客户端。一般开发中并不会用JDK原生NIO,原因如下:

  1. 使用JDK自带的NIO需要了解太多的概念,编程复杂,一不小心bug横飞
  2. Netty底层IO模型随意切换,而这一切只需要做微小的改动,改改参数,Netty可以直接从NIO模型变身为IO模型
  3. Netty自带的拆包解包,异常检测等机制让你从NIO的繁重细节中脱离出来,让你只需要关心业务逻辑
  4. Netty解决了JDK的很多包括空轮询在内的bug
  5. Netty底层对线程,selector做了很多细小的优化,精心设计的reactor线程模型做到非常高效的并发处理
  6. 自带各种协议栈让你处理任何一种通用协议都几乎不用亲自动手
  7. Netty社区活跃,遇到问题随时邮件列表或者issue
  8. Netty已经历各大rpc框架,消息中间件,分布式通信中间件线上的广泛验证,健壮性无比强大

所以,本文选择演示Netty的编解码代码。

在Netty中,我们定义MessageToByteEncoder<T>的继承类,重写其encode函数,来自定义编码器。

public class SocketEncoder extends MessageToByteEncoder<Packet> {
 @Override
 protected void encode(ChannelHandlerContext channelHandlerContext, NetPacket msg, ByteBuf byteBuf) throws Exception {
 byte body[] = msg.getBody();
 int packetLen = body.length;
 // 先设置包长度,然后写入二进制数据
 byteBuf.writeInt(packetLen);
 byteBuf.writeBytes(body);
 }
}

在Netty中,我们定义ByteToMessageDecoder的继承类,重写其decode函数,用来自定义解码器。

public class SocketDecoder extends ByteToMessageDecoder {
 @Override
 void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
 int bufLen = byteBuf.readableBytes();
 // 解决粘包问题(不够一个包头的长度)
 // 4字节是报文中使用了一个int表示了报文长度
 if (bufLen < 4) {
 return;
 }
 // 标记一下当前的readIndex的位置
 byteBuf.markReaderIndex();
 int packetLength = byteBuf.readInt();
 // 读到的消息体长度如果小于我们传送过来的消息长度,则resetReaderIndex。重置读索引,继续接收
 if (byteBuf.readableBytes() < packetLength) {
 // 配合markReaderIndex使用的。把readIndex重置到mark的地方
 byteBuf.resetReaderIndex();
 return;
 }
 NetPacket netPacket = new NetPacket();
 netPacket.setPacketLen(packetLength);
 // 传送过来数据的长度,满足我们的要求了
 byte body[] = new byte[packetLength];
 byteBuf.readBytes(body);
 netPacket.setBody(body);
 list.add(netPacket);
 }
}

更多内容,欢迎关注微信公众号:全菜工程师小辉~



Tags:TCP粘包   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采...【详细内容】
2020-05-29  Tags: TCP粘包  点击:(53)  评论:(0)  加入收藏
基本概念 TCP本质上是数据流,从原理上看,没有包的概念,TCP包对应用程序员可以是透明的。 粘包实际上是把底层包的实现和上层流的概念混在一起。 粘包问题本质上是如何确定数据...【详细内容】
2020-05-25  Tags: TCP粘包  点击:(97)  评论:(0)  加入收藏
TCP是个“流”协议,所谓流,就是没有界限的一串数据。可以想想河里的流水,是连成一片的,其间并没有分界线。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况...【详细内容】
2019-08-28  Tags: TCP粘包  点击:(213)  评论:(0)  加入收藏
▌简易百科推荐
以京训钉开发平台接口文档为例,使用HttpClient类请求调用其接口,对数据进行增删改查等操作。 文档地址: https://www.yuque.com/bjjnts/jxd/bo1oszusing System;using System.C...【详细内容】
2021-12-28  Wednes    Tags:HttpClient   点击:(1)  评论:(0)  加入收藏
阿里云与爱快路由安装组网教程一、开通好阿里云轻量服务器之后在服务器运维-远程连接处进行远程 二、进入控制台后在root权限下根据需要安装的固件位数复制下面命令。32位:wg...【详细内容】
2021-12-28  ikuai    Tags:组网   点击:(1)  评论:(0)  加入收藏
HTTP 报文是在应用程序之间发送的数据块,这些数据块将通过以文本形式的元信息开头,用于 HTTP 协议交互。请求端(客户端)的 HTTP 报文叫做请求报文,响应端(服务器端)的叫做响应...【详细内容】
2021-12-27  程序员蛋蛋    Tags:HTTP 报文   点击:(5)  评论:(0)  加入收藏
一 网络概念:1.带宽: 标识网卡的最大传输速率,单位为 b/s,比如 1Gbps,10Gbps,相当于马路多宽2.吞吐量: 单位时间内传输数据量大小单位为 b/s 或 B/s ,吞吐量/带宽,就是网络的使用率...【详细内容】
2021-12-27  码农世界    Tags:网络   点击:(3)  评论:(0)  加入收藏
1.TCP/IP 网络模型有几层?分别有什么用? TCP/IP网络模型总共有五层 1.应用层:我们能接触到的就是应用层了,手机,电脑这些这些设备都属于应用层。 2.传输层:就是为应用层提供网络...【详细内容】
2021-12-22  憨猪哥08    Tags:TCP/IP   点击:(35)  评论:(0)  加入收藏
TCP握手的时候维护的队列 半连接队列(SYN队列) 全连接队列(accepted队列)半连接队列是什么?服务器收到客户端SYN数据包后,Linux内核会把该连接存储到半连接队列中,并响应SYN+ACK报...【详细内容】
2021-12-21  DifferentJava    Tags:TCP   点击:(10)  评论:(0)  加入收藏
你好,这里是科技前哨。 随着“元宇宙”概念的爆火,下一代互联网即将到来,也成了互联网前沿热议的话题,12月9日美国众议院的听证会上,共和党议员Patrick McHenry甚至宣称,要调整现...【详细内容】
2021-12-17  王煜全    Tags:Web3   点击:(14)  评论:(0)  加入收藏
一、demopublic static void main(String[] args) throws Exception { RetryPolicy retryPolicy = new ExponentialBackoffRetry( 1000, 3);...【详细内容】
2021-12-15  程序员阿龙    Tags:Curator   点击:(22)  评论:(0)  加入收藏
一、计算机网络概述 1.1 计算机网络的分类按照网络的作用范围:广域网(WAN)、城域网(MAN)、局域网(LAN);按照网络使用者:公用网络、专用网络。1.2 计算机网络的层次结构 TCP/IP四层模...【详细内容】
2021-12-14  一口Linux    Tags:网络知识   点击:(31)  评论:(0)  加入收藏
无论是在外面还是在家里,许多人都习惯了用手机连接 WiFi 进行上网。不知道大家有没有遇到过这样一种情况, 明明已经显示成功连接 WiFi,却仍然提示“网络不可用”或“不可上网”...【详细内容】
2021-12-14  UGREEN绿联    Tags:WiFi   点击:(25)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条