| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 网络协议 -> 深入理解什么是TCP 粘包?粘包警察是什么梗? -> 正文阅读 |
|
[网络协议]深入理解什么是TCP 粘包?粘包警察是什么梗? |
一、前言?本文围绕 TCP 协议展开,先来回顾下 TCP 协议的特点:
粘包警察由来?粘包由来?粘包警察 ,一词首次看到是在 v2。粘包警察认为 “粘包” 这词侮辱了 TCP,在 TCP 下讨论 “粘包” 是伪命题。相反,粘包学家认为 “粘包” 就是 TCP 问题。遂粘包警察频频现身『TCP粘包』帖子下,试图改正这偏见,提醒各位: TCP 是面向字节流的。 据说以前有一群基础不扎实的程序员经常使用 VC 写各种 Windows 客户端程序,喜欢使用 UDP 编程(VC 的 UDP 编程,代码简单,收发逻辑简单明)。 因为通讯应用的复杂性以及需求需要,他们尝试将多条数据放在一个 UDP 数据包里进行发送,遂碰到『粘包问题』。同时他们开始接触并使用 TCP,惯性思维套用之前 UDP 编程方式来使用 TCP,非常容易遇到所谓的 『粘包问题』。随着硬件升级,多物理核的 CPU 普及,多线程与并行编程开始流程,对程序员基本功提出更高的要求,这群人仍在并行程序使用串行思维进行编程,必定遇到『粘包问题』。 于是这群人把这个问题总结出来,称之为 『粘包问题』。 书籍《Netty 权威指南》中第四章标题就是 “TCP粘包/拆包问题的解决之道”,影响了一批批使用 Java 和 Netty 的编程者。 什么是粘包/拆包?所谓粘包: 就是几个数据包粘在一起了,如果要处理得先拆包。 所谓拆包: 就是收到一批数据包碎片,要把这些碎片粘起来才能合成一个完整的数据包。 举个栗子:客户端发送数据给服务端,可能会出现以下五种情况:
小结: 由于拆包/粘包问题的存在,如何识别一个完整的数据包就成了问题?难点在于如何定义一个数据包的边界。 C/C++Linux服务器开发高级架构师/C++后台开发架构师?免费学习地址 【文章福利】另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以自行添加:Q群:720209036 点击加入~ 群文件共享 为什么会有人说 TCP 粘包?先来看下应用程序使用 TCP 套接字的流程: 对应 TCP/IP 4层协议
这里解释下 MSS 和 MTU:
MTU 和 MSS 一般的计算关系为:MSS = MTU - IP 首部 - TCP首部。 『粘包学家』认为 TCP 粘包/拆包发生原因有三:
说白了,『粘包学家』认为我怎么给你的,你就该怎么还给我。 『粘包警察』认为这根本不是 TCP 的锅:
说白了,『粘包警察』认为怎么解析数据是你应用层的问题,TCP 只管传输并提供可靠的交付服务。 拓展:Nagle 算法Nagle 算法于 1984 年被福特航空和通信公司定义为 TCP/IP 拥塞控制方法,这使福特经营的最早的专用 TCP/IP 网络减少拥塞控制,从那以后这一方法得到了广泛应用。 优势:为了尽可能发送大块数据,避免网络中充斥着许多小数据块 如果每次需要发送的数据只有 1 字节,加上 20 个字节的 IP首部 和 20 个字节的 TCP首部,每次发送的数据包大小为 41 字节,但是只有 1 字节是有效信息,这就造成了非常大的浪费。 Nagle 算法的规则(可参考tcp_output.c 文件里 tcp_nagle_check 函数注释):
Linux 在默认情况下是开启 Nagle 算法的,在大量小数据包的场景下可以有效地降低网络开销。
Tips: 还有一个延迟 ACK(Delay ACK),TCP 何时发送 ACK 有如下规定:
拓展:UDP 为什么不分段?先来回顾下 UDP 的特点:
?再看 UDP 数据报格式: ?可知一个 UDP 数据报可携带最大用户数据长度为:2^16 - 8 = 65535 - 8 = 65527 (B) 小结下 UDP 为什么不分段? 1.UDP 协议特性: 面向报文。16位UDP 长度。 没有分段的能力:标记分段先后顺序的能力,即编号(ID)、尾部编号的标识 (Flag) 2.UDP 应用特性: 常用于一次性传输比较少量数据的网络应用,如 DNS、SNMP 等。 当 DNS 查询超过 512字节 时,协议的 TC 标志出现删除标志,这时则使用 TCP 发送。 通常传统的 UDP 报文一般不会大于512字节。 二、拆包/粘包解决方案由上文可知我们需要一种定义来数据包的边界,这也是解决拆包/粘包的唯一方法:定义应用层的通信协议。 主流协议解决方案有:
Netty 对三种常用封帧方式的支持:
(1)固定消息长度Netty 中提供了类 FixedLengthFrameDecoder:
项目地址:对应代码
通过 telnet 去访问:telnet localhost 8088 ?优缺点:
(2)特殊分隔符既然接收方无法区分消息的边界,那么可以在每次发送报文的尾部加上特定分隔符,接收方就可以根据特殊分隔符进行消息拆分。 DelimiterBasedFrameDecoder 自动完成以分隔符做结束标志的消息的解码:
项目地址:代码
通过 telnet 去访问:telnet localhost 8088 比较推荐的做法是:将消息进行编码,例如 base64 编码,然后可以选择 64 个编码字符之外的字符作为特定分隔符。 特定分隔符法在消息协议足够简单的场景下比较高效,Redis 在通信过程中采用的就是换行分隔符。
(3)消息长度 + 消息内容消息长度 + 消息内容是项目开发中最常用的一种协议,如下展示了该协议的基本格式。
消息头中存放消息的总长度,例如使用 4 字节的 int 值记录消息的长度,消息体实际的二进制的字节数据。 接收方在解析数据时:
依然以上述提到的原始字节数据为例,使用该协议进行编码后的结果如下所示:
消息长度 + 消息内容的使用方式非常灵活,且不会存在消息定长法和特定分隔符法的明显缺陷。 当然在消息头中不仅只限于存放消息的长度,而且可以自定义其他必要的扩展字段:
原文链接:https://juejin.cn/post/7135839422360551455 |
|
网络协议 最新文章 |
使用Easyswoole 搭建简单的Websoket服务 |
常见的数据通信方式有哪些? |
Openssl 1024bit RSA算法---公私钥获取和处 |
HTTPS协议的密钥交换流程 |
《小白WEB安全入门》03. 漏洞篇 |
HttpRunner4.x 安装与使用 |
2021-07-04 |
手写RPC学习笔记 |
K8S高可用版本部署 |
mySQL计算IP地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 20:36:30- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |