TCP与UDP的区别、TCP的粘包、拆包
TCP和UDP的区别
TCP是一个面向连接的,客户端与服务端、可靠的,基于字节流的传输层协议。双方互相通信之前,T CP需要三次握手建立连接,而UDP没有建立连接的过程。
UDP是一个面向无连接的传输层协议,UDP的数据是基于数据报的。
- 连接 UDP是无连接的 TCP是面向连接的
- 可靠 UDP是不可靠传输,不使用流量控制和拥塞控制, TCP是可靠传输,使用流量控制和拥塞控制
- 连接对象个数 UDP支持一对一、一对多、多对一和多对多交互通信, TCP只能是一对一通信
- 传输方式 UDP是面向报文,TCP是面向字节流的
- 首部开销 UDP首部开销小,8字节 , TCP首部开销大,最小20字节,最大60字节
粘包、拆包
假设🈶️2个数据包,没有发生粘包和拆包情况:
粘包:
拆包:
产生TCP粘包和拆包的原因:tcp是以流动的方式传输数据,传输的最小单位为一个报文段(segment)。tcp Header中有个Options标识位,常见的标识为mss(Maximum Segment Size) (TCP数据报中数据部分字节的最大值),连接层每次传输的数据有个最大限制MTU(Maximum Transmission Unit)(数据链路层一个帧的最大值),一般是1500比特,超过这个量要分成多个报文段,mss则是这个最大限制减去TCP的header,光是要传输的数据的大小,一般为1460比特。换算成字节,也就是180多字节。
tcp为提高性能,发送端会将需要发送的数据发送到缓冲区,等待缓冲区满了之后,再将缓冲中的数据发送到接收方。同理,接收方也有缓冲区这样的机制,来接收数据。
原因:
- 应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。
- 应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包。(因为要缓冲区满了才进行发送)
- 进行mss(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>mss的时候将发生拆包。 (recv到第一片数据是不能去处理业务逻辑的,要判断什么时候recv完整)
- 接收方法不及时读取套接字缓冲区数据,这将发生粘包。
解决方案:
- 使用带消息头的协议、消息头存储消息开始标识及消息长度信息,服务端获取消息头的时候解析出消息长度,然后向后读取该长度的内容。("可以制定 首部固定多少个字节长度为数据包的长度,不够就补0")
- 设置定长消息,服务端每次读取既定长度的内容作为一条完整消息。
- 设置消息边界,服务端从网络流中按消息编辑分离出消息内容。 (比如弄个"\n")
linux 下的epoll lt模式下的做法:
1.准备一个4字节变量用于容纳头部数据,另外用一个整形表示头部数据读到第几个字节了(因为有可能一次读不满4字节)
2.读完头部4字节后,就知道长度,开始分配缓冲区,然后从socket读到缓冲区,这里要注意可能eagain,这种情况直接等下一次读消息到来再继续读。
3.直到读满缓冲区就代表数据完整了,然后可以通知上层过来拿数据了。因为我们使用的是lt模式,一次不必读取完socket里的数据,而且这种做法也没有多读数据,不会造成粘包问题
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报