数据包的传输过程详解及TCP沾包问题

2023-11-19

目录

TCP沾包问题


5个基本知识点:

  1. 封装报文是从上层到下层(应用层 --> 传输层 --> 网络层 – > 数据链路层 --> 物理层),解封装报文是从下层到上层。
  2. 数据包传输的过程中,源IP和目标IP不会变,除非遇到NAT(SNAT或DNAT),源MAC和目标MAC遇到网关会变。
  3. 二层内通过MAC寻址,三层通过IP寻址。
  4. 当一个数据包的目的地址不是本机,所以需要查询路由表,当查到路由表中的网关之后,需要获取网关的MAC地址,并将数据包的MAC地址修改成网关地址,然后发送到对应的网卡。
  5. 协议数据单元在应用层、表示层和会话层被称做数据(Data),在传输层被称做分段(Segment),在网络层被称做包(Packet),在数据链路层被称做帧(Frame),在物理层被称做比特(Bit)
  6. PC1或者Server上保留的arp表是:arp和ip的映射关系。而二层交换机是arp和端口的映射关系,也就是这个arp 应该由哪个端口转发。三层交换机可以保留arp和ip的映射关系。

应用层:HTTP协议是生成针对目标WEB服务器的HTTP请求报文,该报文就是需要传递的数据

传输层:HTTP协议使用的是TCP协议,为了方便通信,将HTTP请求报文按序号分为多个报文段(segment),并对每个报文段进行封装。PC1使用本地一个大于1024以上的随机TCP源端口(这里假设是1030)建立到目的服务器TCP80号端口的连接,TCP源端口和目的端口加入到报文段中,学名叫协议数据单元(Protocol Data Unit, PDU)。因TCP是一个可靠的传输控制协议,传输层还会加入序列号、窗口大小等参数

网络层:下沉到网络层后,封装网络层的头部,主要就是添加源和目的IP地址,成为数据包。用户通常使用主机名或域名来访问服务器,这时就需要通过应用层的DNS服务来通过域名查找IP地址,或逆向从IP地址反查域名。这里的源IP地址是193.1.1.2,目的IP地址是195.1.1.2。

数据链路层:下沉到数据链路层,封帧的头部,src mac和dst mac。PC1比较去往的目标IP,发现Server IP 195.1.1.2不在本地网络中,PC1通过查找本地路由表,会有一条默认路由指向网关R1,知道数据包要先发到网关R1的Fa0/0口。PC1查找本地arp cache,如果找到193.1.1.1对应的MAC地址则进行封装; 如果在ARP cache中没有找到193.1.1.1对应的MAC地址,则用ARP协议,査询到网关对应的MAC地址 “00-11-BC-7D-25-03” 。于是,这里的源MAC地址是PC1的MAC地址“00-1B-24-7D-25-01”,目的MAC地址是网关的MAC地址 “00-11-BC-7D-25-03。

物理层:数据链路层封装后的数据帧下沉到物理层,转换成二进制形式的比特(Bit)流,从PC1的网卡发送出去

        然后在物理层,数据链路层,网络层,通过对数据包的解封再封装等操作,获得这个包的MAC和IP地址,在局域网和异构的网络中进行查找并传输,到达目的主机后在进行上层的解封,获得数据。

从这个流动过程中,可以发现数据流在中间设备上主要执行的是OSI下三层的操作。

  • 物理层的设备不改变帧的格式,广播式转发。
  • 数据链路层的设备也不改变帧的格式,但可以根据数据帧中的目的MAC地址进行转发;
  • 网络层的设备改变帧的格式,要执行帧的解封装和再封装,但不改变数据包中的源和目的IP地址

TCP沾包问题

        采用TCP协议进行网络数据传送的软件设计中,普遍存在粘包问题。网络通信采用的套接字(socket)技术,其实现实际是由系统内核提供一片连续缓存(流缓冲)来实现应用层程序与网卡接口之间的中转功能。

        多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估测值大小来进行数据读出,若双方的size不一致时就会使数据包的边界发生错位,导致读出错误的数据分包,进而曲解原始数据含义

        粘包问题的本质就是数据读取边界错误所致。

        此外,发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

二、粘包问题的解决方案

1、定长包
2、包尾加\r\n(ftp)
3、包头加上包体长度

4、更复杂的应用层协议

设计方案一:定长发送

        在进行数据发送时采用固定长度的设计,也就是无论多大数据发送都分包为固定长度(为便于描述,此处定长为记为LEN),也就是发送端在发送数据时都以LEN为长度进行分包。这样接收方都以固定的LEN进行接收,如此一来发送和接收就能一一对应了。分包的时候不一定能完整的恰好分成多个完整的LEN的包,最后一个包一般都会小于LEN,这时候最后一个包可以在不足的部分填充空白字节。

        当然,这种方法会有缺陷。

        1.最后一个包的不足长度被填充为空白部分,也即无效字节序。那么接收方可能难以辨别这无效的部分,它本身就是为了补位的,并无实际含义。这就为接收端处理其含义带来了麻烦。当然也有解决办法,可以通过增添标志位的方法来弥补,即在每一个数据包的最前面增加一个定长的报头,然后将该数据包的末尾标记一并发送。接收方根据这个标记确认无效字节序列,从而实现数据的完整接收。

        2.在发送包长度随机分布的情况下,会造成带宽浪费。比如发送长度可能为 1,100,1000,4000字节等等,则都需要按照定长最大值即4000来发送,数据包小于4000字节的其他包也会被填充至4000,造成网络负载的无效浪费。

2.2  设计方案二:尾部标记序列

        在每个要发送的数据包的尾部设置一个特殊的字节序列,此序列带有特殊含义,跟字符串的结束符标识”\0”一样的含义,用来标示这个数据包的末尾,接收方可对接收的数据进行分析,通过尾部序列确认数据包的边界。

这种方法的缺陷较为明显:

        1.接收方需要对数据进行分析,甄别尾部序列。

        2.尾部序列的确定本身是一个问题。什么样的序列可以向”\0”一样来做一个结束符呢?这个序列必须是不具备通常任何人类或者程序可识别的带含义的数据序列,就像“\0”是一个无效字符串内容,因而可以作为字符串的结束标记。那普通的网络通信中,这个序列是什么呢?我想一时间很难找到恰当的答案。

2.3  设计方案三:头部标记分步接收

        这个方法的实现是这样的,定义一个用户报头,在报头中注明每次发送的数据包大小。接收方每次接收时先以报头的size进行数据读取,这必然只能读到一个报头的数据,从报头中得到该数据包的数据大小,然后再按照此大小进行再次读取,就能读到数据的内容了。这样一来,每个数据包发送时都封装一个报头,然后接收方分两次接收一个包,第一次接收报头,根据报头大小第二次才接收数据内容。(此处的data[0]的本质是一个指针,指向数据的正文部分,也可以是一篇连续数据区的起始位置。因此可以设计成data[user_size],这样的话。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据包的传输过程详解及TCP沾包问题 的相关文章

随机推荐

  • 机器学习:多分类的logistic回归

    机器学习 多分类的logistic回归 Multi Class Logistic 多分类的Logistic问题 它适用于那些类别数大于2的分类问题 并且在分类结果中 样本x不是一定只属于某一个类可以得到样本x分别属于多个类的概率 也可以说样
  • Unity3D【脚本】 按键盘Esc弹出退出面板 确定退出游戏 取消关闭面板

    按键盘Esc弹出退出面板 确定退出游戏 取消关闭面板 效果图 脚本 using UnityEngine using System Collections public class Exit MonoBehaviour public Game
  • 【Xilinx】SynchronousInterruptHandler错误排查笔记

    SynchronousInterruptHandler错误排查笔记 一 ArmV8的异常处理 二 64位lscript ld的修改 三 asm vectors S的修改 四 SynchronousInterruptHandler函数解析 五
  • 一篇文章学会使用摩斯密码,简单易懂,你也可以使用“降维打击”

    阅读之前 大家请先看一行符号 看看大家能不能猜出这段符号所代表的含义 相信能看出这段符号含义的人还是占少数 没关系 通过阅读久见菌的这篇文章保证让你能看懂这是什么意思 摩尔斯电码的发明 上面这一串符号就是使用摩尔斯电码打出来的英语单词 摩尔
  • Latex特殊符号大全(高清)

    Latex符号大全 转载内容供自己阅读 原文 Latex特殊符号大全 高清
  • Cmake学习

    Cmake学习 CMake调用boost的编译脚本 cmake minimum required VERSION 3 14 project boost python 设置支持C 11特性 set CMAKE CXX STANDARD 11
  • 鸟哥的Linux私房菜PDF在线阅读

    鸟哥的Linux私房菜在线阅读 我在网上查了好久都没有找到正经的关于鸟哥的linux私房菜的PDF版本 要么就是耍流氓的要钱 给了钱 也不一定能得到完整版的PDF 我也只找到了在线版的 在这里供献出来 仅供大家学习参考之用 至于PDF版的
  • 如何查看linux服务器是否为amd64架构还是x86_64架构

    前言 环境 centos 7 9 我们在下载软件时 软件包后面通常带有amd64的字样 那么如何知道我们的服务器是不是amd64架构呢 下面的这些命令可以查看linux的版本及其他信息 查看linux内核版本 root master cat
  • 计算机网络-应用层协议2(FTP)

    1 文件传输协议 FTP 原理 如图所示 FTP工作原理如下 用户或主机通过FTP用户接口与FTP客户进程交互 该用户首先提供远程主机的主机名 使本地主机的FTP客户进程建立一个到远程FTP服务器进程的TCP连接 紧接着该用户提供用户标识和
  • 各种Java加密算法

    如基本的单向加密算法 BASE64 严格地说 属于编码格式 而非加密算法 MD5 Message Digest algorithm 5 信息摘要算法 SHA Secure Hash Algorithm 安全散列算法 HMAC Hash Me
  • 华为Atlas200dk使用第三步------只用一根网线登录华为开发板

    华为开发板Atlas200DK ARES500DK开发板 开发板使用心得系列文章目录 第三章 一根线登录华为开发板 目录 前言 同时使用网线和串口线连接开发板有点多余 线多显得乱 串口连接开发板也比较繁琐 因此本文给大家提供两种使用一根网线
  • FLutter Error: ADB exited with exit code 1 Performing Streamed Install

    出现这个原因是模拟器存储空间满了没办法安装运行新的应用 打开模拟器界面将原先一些不要的应用卸载了就能安装了
  • C语言中的基本输入输出

    目录 1 字符输出函数putchar 2 字符输入函数getchar 3 格式化输出函数printf 4 格式化输入函数scanf 5 字符串接收函数gets 6 字符串接收函数fgets 7 字符串输出函数puts 8 格式化转换为字符串
  • R语言【数据集的导入导出】

    目录 一 从键盘输入数据 二 函数方法读取 1 读取数据文件 2 从屏幕读取数据 1 scan 2 readline 3 读取固定宽度数据文件 三 读取csv文件 四 读取表格数据文件 五 从网络中读取表格或者CSV数据文件 一 从键盘输入
  • ip地址段分解与合并

    1 为什么要分解和合并ip地址段 无他 工作需要嘛 谁没事去划分ip地址段 优点 可以节省大量的时间 减少算错的可能性 2 工具下载 下载链接 https github com zhanhb cidr merger github在国内使用不
  • 如何查询Oracle数据库的操作日志

    Oracle数据库里有一个专门存储操作的视图 v sqlarea 可以通过它查询历史操作 select t SQL TEXT t FIRST LOAD TIME from v sqlarea t where t SQL TEXT like
  • linux下vbox+chrome os安装体验

    1 安装虚拟机 VirtualBox sudo apt install virtualbox 2 下载chrome OS ISO 文件 http www getchrome eu download 3 过程
  • CUDA小白 - NPP(6) 图像处理 Geometry Transforms (1)

    cuda小白 原始API链接 NPP GPU架构近些年也有不少的变化 具体的可以参考别的博主的介绍 都比较详细 还有一些cuda中的专有名词的含义 可以参考 详解CUDA的Context Stream Warp SM SP Kernel B
  • opencl入门

    openCL开发 绪论 知乎 OpenCL中文入门完整教程 opencl教程 其它文档类资源 CSDN下载 OpenCL中文入门完整教程 opencl教程 其它文档类资源 CSDN下载
  • 数据包的传输过程详解及TCP沾包问题

    目录 TCP沾包问题 5个基本知识点 封装报文是从上层到下层 应用层 gt 传输层 gt 网络层 gt 数据链路层 gt 物理层 解封装报文是从下层到上层 数据包传输的过程中 源IP和目标IP不会变 除非遇到NAT SNAT或DNAT 源M