【基础夯实】TCP/IP 协议是怎么控制数据收发

news2024/9/17 8:18:04

【基础夯实】TCP/IP 协议是怎么控制数据收发

网址输入到页面完整显示,对于此问题,粗略的解释可以分为以下几个步骤:

  1. 客户端通过 HTTP 协议对数据进行一次包装
  2. 通过 DNS 服务器(本地无缓存)解析网址的 ip 地址
  3. 通过 TCP 协议与目标 IP 建立连接,二次包装的数据包在网线和路由器完成传递
  4. 返回结果经过浏览器的绘制和渲染,完成页面的构建

对于第三点 TCP/IP 协议是怎么来控制数据在网络中的传递一知半解,最近查阅相关网络方面的书籍才彻底搞懂其原理。

数据收发概览

应用程序发起网络请求后,数据的收发实际是委托给 Socket 库来完成,其操作大致可以分为以下4个阶段:

  1. 创建套接字(创建套接字阶段)
  2. 将管道连接到服务器端的套接字上(连接阶段)
  3. 收发数据(通信阶段)
  4. 断开管道并删除套接字(断开阶段)

下图是这四个阶段的图例:
在这里插入图片描述

Socket 库是一组编程接口(API),用于在不同计算机之间通过网络进行双向通信。它是由操作系统层面提供的,允许应用程序创建网络连接并收发数据。Socket 库抽象了底层的网络细节,使得程序员可以通过一组标准的函数调用来实现网络通信,而无需直接处理复杂的网络协议细节。

Socket 库提供了创建、配置和管理socket的一系列函数,其中包括 socket()connect()write()read()close() 等方法

Socket 完成数据的收发过程是通过协议栈来完成,协议栈的内部及所处位置如下图所示

在这里插入图片描述

图中最上层是应用程序,它们会将收发数据等工作委派给 Socket 库来完成,Socket库包括解析器,解析器用来向DNS服务器发出查询。

第二层就是操作系统内部,协议栈位于该层。协议栈有两部分,上半部分是 TCP 和 UDP 协议,主要用来控制数据连接。下半部分是 IP 协议,控制网络包收发的操作。在互联网上传送数据时,数据会被切分成一个一个的网络包A,而将网络包发送给通信对象的操作就是由IP来负责的。此外,IP中还包括 ICMPA 协议和 ARPB 协议。ICMP 用于告知网络包传送过程中产生的错误以及各种控制消息,ARP 用于根据IP地址查询相应的以太网MAC地址。

创建套接字

协议栈是根据套接字中记录的控制信息来工作的

调用 <描述符> = socket(<使用的ip>,<流模式>,...) 方法(伪代码)后,在协议栈内部会创建一块用于存放控制信息的内存空间,这里记录了用于控制通信操作的控制信息,例如通信对象的IP地址、端口号、通信操作的进行状态等,可以说这些控制信息就是套接字的实体,或者说存放控制信息的内存空间就是套接字的实体。在Windows中可以用netstat命令显示套接字内容:

在这里插入图片描述

连接服务器

创建套接字之后,应用程序(浏览器)就会调用 connect(<描述符>,<服务器的ip和端口号>) 方法(伪代码),随后协议栈会将本地的套接字与服务器的套接字进行连接。数据包在连接的过程变化如下:

  1. 客户端 TCP 模块:先创建一个包含表示开始数据收发操作的控制信息的 TCP 头部,同时将头部标志位的 SYN 设置为1,此外还需要设置适当的序号和窗口大小。当 TCP 头部创建好之后,TCP 模块会将数据传递给 IP 模块并委托它进行发送。
  2. 客户端 IP 模块:IP 模块会在数据头部再添加以太网和 IP 的头部信息,处理后的数据包会通过网线和路由器传递给服务端。数据如果丢失会重新发送。
  3. 服务端 IP 模块:IP 模块会将接收到的数据传递给 TCP 模块
  4. 服务器的 TCP 模块:根据 TCP 头部中的端口号找到该端口对应的套接字。当找到对应的套接字之后,套接字中会写入相应的信息,并将状态改为正在连接。上述操作完成后,会对将要返回的数据的 TCP 头部中设置发送方和接收方端口号,SYN 和 ACK控制位置1。接下来,服务器TCP模块会将TCP头部传递给IP模块,并委托IP模块向客户端返回响应。

下图是传输过程中数据包的结构

在这里插入图片描述

为了创建稳定的连接,TCP 模块会通过三次握手来完成连接,过程如下图,其中 ACK 号改为 x+1 是为了数据的分包,原理将在收发数据时进行讲解。

在这里插入图片描述

【扩展知识】IP和TCP协议头部格式

TCP 协议头部格式

在这里插入图片描述

  • 源端口(Source Port)和目标端口(Destination Port):分别占用16位,表示源端口号和目的端口号;用于区别主机中的不同进程, 而IP地址是用来区分不同的主机的,源端口号和目的端口号配合上IP首部中的源IP地址和目的IP地址就能唯一的确定一个TCP连接;
  • 序号(Sequence Number):占用32位,表示发送数据的顺序编号,发送方告知接收方该网络包发送的数据相当于所有发送数据的第几个字节。主要用来解决网络报乱序的问题;
  • 确认号(Acknowledgment Number):占用32位,表示接收数据的顺序编号,接收方告知发送方接收方已经收到了所有数据的第几个字节,因此,确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK标志(下面介绍)为1时该确认序列号的字段才有效。主要用来解决不丢包的问题;
  • 数据偏移(Offset):占用4位,表示数据部分的起始位置,也可以认为表示头部的长度
  • 标志位(TCP Flags):占用6位,该字段中的每个比特分别表示以下通信控制含义
    • URG:此标志表示TCP包的紧急指针有效,用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据;
    • ACK:表示接收数据序号字段有效,一般表示数据已被接收方收到;
    • PSH:表示通过 flush 操作发送的数据。所谓 flush 操作就是指在数据包到达接收端以后,立即传送给应用程序, 而不是在缓冲区中排队;
    • RST:强制断开连接,用于异常中断的情况。用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包;
    • SYN:发送方和接收方相互确认序号,表示连接操作。SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1, ACK=0;连接被响应的时候,SYN=1,ACK=1;这个标志的数据包经常被用来进行端口扫描。扫描者发送 一个只有SYN的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口;但是由于这 种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全 的主机将会强制要求一个连接严格的进行TCP的三次握手;
    • FIN:表示断开连接
  • 窗口(Window):占用16位,接收方告知发送方窗口大小(即无需等待确认可一起发送的数据量),用来进行流量控制。
  • 检验和:占用16位,检验TCP数据报首部是否出现错误。
  • 紧急指针:占用16位,表示应紧急处理的数据位置

IP 协议头部格式

在这里插入图片描述

  • 版本号:占用4位,用于指示IP数据报使用的IP协议版本
  • 首部长度:占用4位,IP 头部的长度。可选字段可导致头部长度变化,因此这里需要指定头部的长度
  • 服务类型:占用8位,在最初这个字段有一部分用于定义数据包的优先级,剩下的一部分定义了服务类型。IETF已经改变了这个8位字段的解释,现在定义了一组区分服务。在这种解释中,前6位构成了码点(codepoint),最后两位未使用。当码点字段最右边的3位不全为0时,这6位定义了54种服务(低延时,高吞吐量等等)。
  • 总长度:占用16位,定义了数据报总长度,其以字节为单位。故IPv4数据报总长度上限值位65536字节。注:为什么需要这个字段?在许多情况下,我们确实不需要这个字段值。但是有些情况下,封装在一个帧里的并不仅仅是数据报,还可能附加了一些填充。比如,以太网协议对帧的数据有最大值(1500字节)和最小值(46字节)的限制,当数据小于46字节时,数据将含有填充数据。
  • 标识(identification):占用16位,用于识别包的编号,一般为包的序列号。如果一个包被 IP 分片,则所有分片都拥有相同的 ID。
  • 标志(flag):占用3位,第一位保留(未用),剩下两位分别代表是否允许分片,以及当前包是否为分片包
  • 分片偏移:占用13位,表示当前包的内容为整个 IP 消息的第几个字节开始的内容
  • 生存时间:占用8位,表示包的生存时间,这是为了避免网络出现回环时一个包永远在网络中打转。每经过一个路由器,这个值就会减 1,减到 0 时这个包就会被丢弃
  • 协议号:占用8位,定义了使用IPv4服务的高层协议,如TCP,UDP,ICMP,IGMP,OSPF等的数据都将被封装到IP数据报中。这个字段指明数据报必须交付给哪个最终目的协议。
  • 检验和:占用16位,用于检查错误,现在已不使用。
  • 源地址:占用32位,网络包发送方的 IP 地址
  • 目的地址:占用32位,网络包接收方的 IP 地址

收发数据

当控制流程从 connect 回到应用程序之后,接下来就进入数据收发阶段了。数据收发操作是从应用程序调用 write(<描述符>,<发送数据>,<数据长度>) (伪代码)开始的,该方法执行后应用程序将数据交给协议栈,协议栈收到数据后执行发送操作。

协议栈并不是一收到数据就马上发送出去,而是会将数据存放在内部的发送缓冲区中,等到数据积累到一定量时再发送出去。至于要积累多少数据才能发送,则需要根据以下两个因素来判断:

  • 一个网络包能容纳的数据长度(MTU),以太网中一般为 1500 字节。(补充:除去头部之后,一个网络包所能容纳的 TCP 数据的最大长度,称为MSS)
  • 等待时间,当等待时间到达后,即便缓冲区中的数据长度没有达到MSS,也应该果断发送出去

在这里插入图片描述

当需要发送的数据(博客或论坛的长文)超过了 MSS 时,缓冲区中的数据会被以 MSS 长度为单位进行拆分,拆分出来的每块数据会被放进单独的网络包中。当判断需要发送这些数据时,就在每一块数据前面加上 TCP 头部,并根据套接字中记录的控制信息标记发送方和接收方的端口号,然后交给IP模块来执行发送数据的操作。

在这里插入图片描述

在数据发送过程中传输的可靠性和流量控制是两个需要重点理解的点,以上两点都是通过 TCP 协议来控制的。

TCP 可靠传输的实现

使用 ACK 号确认网络包已收到

单向数据传输

在这里插入图片描述

当发送方数据超过 MSS 时,会将数据拆分成多个网络包。发送方将包的序号和长度发送给接收方,接收方拿到包后将值+1作为 ACK 号(如果序号为2,长度为1460,则 ACK 号为 1462,公式为:序号+长度 -1 + 1)发送给发送方。在实际的通信中,为了防止信号被截取破译,序号并不是从1开始的,而是需要用随机数计算出一个初始值。

通过序号,长度,ACK 号的机制既能知道网络包对方是否有接受到,也能知道数据包是否有遗漏

双向数据传输

在这里插入图片描述

了解了单向数据传输后,我们来总结下双向数据传递完整的工作原理。

连接操作(三次握手):

  1. 第一次握手:客户端在连接时需要计算出与从客户端到服务器方向通信相关的序号初始值,并将这个值发送给服务器
  2. 第二次握手:服务器会通过这个初始值计算出ACK号并返回给客户端。客户端传递过来的初始值有可能在通信过程中丢失,因此当服务器收到初始值后需要返回ACK号作为确认。同时,服务器也需要计算出与从服务器到客户端方向通信相关的序号初始值,并将这个值发送给客户端
  3. 第三次握手:客户端也需要根据服务器发来的初始值计算出ACK号并返回给服务器

收发操作:数据先由客户端向服务器发送请求,序号也会跟随数据一起发送(右图④)。然后,服务器收到数据后再返回ACK号(右图⑤)。从服务器向客户端发送数据的过程则正好相反(右图⑥⑦)

TCP 的流量控制

TCP 的流量控制就是控制网络包发送的等待时间,根据接收方返回的 ACK 号动态调整发送速率,保证接收方来得及接收或者更快的接收。

利用滑动窗口实现 TCP 流量控制

TCP 通过 ACK 号能实现可靠的数据传递,但在等待 ACK 号的这段时间中,如果什么都不做那实在太浪费了。为了减少这样的浪费,TCP 采用滑动窗口方式来管理数据发送和 ACK 号的操作。

所谓滑动窗口,就是在发送一个包之后,不等待ACK号返回,而是直接发送后续的一系列包。这样一来,等待ACK号的这段时间就被有效利用起来了。

在这里插入图片描述

当使用滑动窗口方式后,接收端会连续收到数据包。接收方的 TCP 收到包后,会先数据包存放到接收缓冲区中,但当包的发送速度 > 服务器的处理速度,缓冲区会溢出导致后续到达的包无法接受而丢失。为了避免这种情况发生,接收方需要告诉发送方自己最多能接收多少数据,然后发送方根据这个值对数据发送操作进行控制,这就是滑动窗口方式的基本思路。

关于滑动窗口的具体工作方式,通过下图更容易理解。

在这里插入图片描述

在这张图中,接收方将数据暂存到接收缓冲区中并执行接收操作。当接收操作完成后,接收缓冲区中的空间会被释放出来,也就可以接收更多的数据了,这时接收方会通过TCP头部中的窗口字段将自己能接收的数据量告知发送方。这样一来,发送方就不会发送过多的数据,导致超出接收方的处理能力了。

对于数据的收取,应用程序会调用 read(<描述符>,<接收缓冲区>,...) (伪代码)来获取响应消息。协议栈会尝试从缓存中取出数据并传递给应用程序,如果此时缓存中没有数据,协议栈会将应用程序的委托挂起。当服务端返回数据后,协议栈会将接收到的数据复制到应用程序指定的内存地址中,然后将控制流程交回应用程序。

在这里插入图片描述

断开连接

在断开连接阶段,主要完成两件事:断开 TCP 连接和删除套接字。

TCP 连接的断开可以是服务端也可以是客户端,分为以下四个步骤(四次挥手):

  1. 第一次挥手:服务器(可以使客户端,也可以是服务器端)将 TCP 头部控制位中的FIN比特设为1,协议栈会委托IP 模块向客户端发送数据 。同时,服务器的套接字中也会记录下断开操作的相关信息。
  2. 第二次挥手:当收到服务器发来的 FIN 为1的 TCP 头部时,客户端的协议栈会将自己的套接字标记为进入断开操作状态。然后,为了告知服务器已收到 FIN 为1的包,客户端会向服务器返回一个 ACK 号。上述操作完成后,协议栈就可以等待应用程序来取数据了。客户端应用程序收取数据完成后会调用 close(<描述符>) 来结束数据收发操作。
  3. 第三次挥手:客户端的协议栈也会和服务器一样,生成一个FIN比特为1的 TCP 包,然后委托IP模块发送给服务器。
  4. 第四次挥手:服务器接到数据包后返回ACK号

和服务器的通信结束之后,用来通信的套接字也就不会再使用了,这时我们就可以删除这个套接字了。不过,套接字并不会立即被删除,而是会等待一段时间之后再被删除。

在这里插入图片描述
参考:《网络是怎么连接的》第二章 用电信号传输TCP/IP数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1961334.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

layui 乱入前端

功能包含 本实例代码为部分傻瓜框架&#xff0c;插入引用layui。因为样式必须保证跟系统一致&#xff0c;所以大部分功能都是自定义的。代码仅供需要用layui框架&#xff0c;但原项目又不是layui搭建的提供解题思路。代码较为通用 自定义分页功能自定义筛选列功能行内编辑下拉、…

【React】详解如何获取 DOM 元素

文章目录 一、基础概念1. 什么是DOM&#xff1f;2. 为什么需要获取DOM&#xff1f; 二、使用 ref 获取DOM元素1. 基本概念2. 类组件中的 ref3. 函数组件中的 ref 三、 ref 的进阶用法1. 动态设置 ref2. ref 与函数组件的结合 四、处理特殊情况1. 多个 ref 的处理2. ref 与条件渲…

跟着丑萌气质狗学习WPF——Style样式

Style样式 1. 用法介绍2. 样式多样性3. 全局样式说明和资源字典的使用 1. 用法介绍 提前写好样式&#xff0c;让他作用于所有按钮 <Window x:Class"WPF_Study_Solution.window3"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmln…

typescript 解构时配置类型

以下三种写法&#xff0c;可以参考&#xff1a; const handleMenuClick ({item, key, keyPath}: {item: Object, key: string, keyPath:string}) > {} const handleMenuClick ({item, key, keyPath}: any) > {} interface SomeObj {item: Objectkey: stringkeyPath:st…

计算机系统操作系统简介

目录 1.计算机系统简介 1.1组成结构 1.2系统软件 1.3冯诺依曼计算机特点 1.4硬件构架 2.硬件的进一步认识 2.1存储器 2.2输入设备 2.3输出设备 2.4CPU组成 2.5线的概念引入 3.操作系统 3.1操作系统简介 3.2操作系统如何管理 3.3库函数和系统调用 1.计算机系统简介…

Linux 用户管理模式

目录 1. 概述 2. 管控级别 3. 用户组管理 4. 用户管理 4.1 创建用户 useradd 4.2 删除用户 userdel ​编辑4.3 查看用户所属组 id 4.4 修改用户所属组 usermod 5. 查看用户/用户组 5.1 查看系统用户 5.2 查看系统用户组 1. 概述 Linux 可以配置多个用户&#xff0c…

ppt中国风背景图片去哪找?附6个优质中国风PPT模板分享!

在这个全球化的时代&#xff0c;中国传统文化元素正在各个领域焕发出新的生机&#xff0c;不管是在时尚、建筑还是平面设计领域&#xff0c;中国风都以其独特的美学魅力吸引着世界的目光。在商业演示和学术报告中&#xff0c;PowerPoint(PPT)作为最常用的工具之一&#xff0c;同…

opencv arm 交叉编译

step1.opencv源码文件夹下新建build-arm目录 step2. cmake图像化配置 cmake-gui .. step3. 选择交叉编译 step4.检索交叉编译链路径 step5. 配置 配置install路径 配置编译、链接选项 添加人脸检测模块 config->generate step6. make编译 built-arm目录下&#xff1a; …

DC-DC转换器电感参数详解

我们对DC-DC转换器的要求以及电感参数中的电感值、公差和电阻进行了介绍。本文中&#xff0c;我们将对电感的其它参数进行详细讲解。 自谐频率&#xff08;SRF&#xff09; 每个电感线圈都有一些联带的分布电容&#xff0c;与电感值一起形成一个有自谐频率的并联谐振回路。对…

探索局域网传输新境界 | 闪电藤 v2.2.7

在这个数字化时代&#xff0c;文件的快速、安全传输是我们日常工作中不可或缺的一部分。今天&#xff0c;电脑天空向大家介绍一款革命性的局域网文件传输工具——闪电藤&#xff0c;它将彻底改变你的文件传输体验。 &#x1f3a8; 界面设计 —— 极简之美 闪电藤采用极简的设…

【自动化测试必学语言】python:语言基础

目录 Python 介绍 语言的分类 注释 单行注释 多行注释 变量 定义变量 使用变量 变量名的命名规范 数据类型 数字类型 非数字类型 type() 函数 input输入 print输出 格式化输出 快捷键(小操作) 运算符 算术运算符 比较运算符 Python 介绍 作者&#xff1a; 吉…

【Java】字符串String类(011)

目录 ♦️API和API帮助文档 ♦️创建String &#x1f38f;直接赋值类 &#x1f38f;new类 &#x1f421;空参类 构造方法&#xff1a; 举例代码&#xff1a; &#x1f421;有参类 构造方法&#xff1a; 举例代码&#xff1a; &#x1f421;字符数组类 构造方法&…

如何借助逻辑数据编织平台实现“数据优先堆栈( DFS )”

一、什么是面向“数据优先”的数据研发平台&#xff1f; 企业在数字化转型的浪潮中&#xff0c;愈发认知到数据作为核心战略资产的重要性。然而&#xff0c;要充分利用数据的价值并非易事。一方面&#xff0c;企业需要投入大量资源来建设和维护复杂的数据基础设施&#xff1b;另…

ref函数

Vue2 中的ref 首先我们回顾一下 Vue2 中的 ref。 ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用&#xff0c;引用指向的就是 DOM 元素&#xff1b;如果用在子组件上&#xff0c;引用就指向组件实例&#xff1…

计算机基础(day1)

1.什么是内存泄漏&#xff1f;什么是内存溢出&#xff1f;二者有什么区别&#xff1f; 2.了解的操作系统有哪些&#xff1f; Windows&#xff0c;Unix&#xff0c;Linux&#xff0c;Mac 3. 什么是局域网&#xff0c;广域网&#xff1f; 4.10M 兆宽带是什么意思&#xff1f;理论…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 整数数组按个位数字排序(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆Coding ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 93 分 最新华为OD机试目录…

使用大型语言模型进行文档解析

动机 多年来&#xff0c;正则表达式一直是我解析文档的首选工具&#xff0c;我相信对于许多技术人员和行业也是如此。尽管正则表达式在某些情况下非常强大&#xff0c;但它们常常在面对真实世界文档的复杂性和多样性时缺少灵活性。 另一方面&#xff0c;大型语言模型提供了一…

Mysql输出今年1月至当前月份日期序列

#今日2024-07-29SELECTDATE_FORMAT( DATE_ADD( NOW(), INTERVAL -(CAST( help_topic_id AS SIGNED INTEGER )) MONTH ), %Y-%m ) monthsFROMmysql.help_topicWHEREhelp_topic_id < TIMESTAMPDIFF(MONTH, CONCAT(DATE_FORMAT(CURDATE(), "%Y-01-01")),CONCAT(STR_…

《动手做科研 》| 03. 如何阅读人工智能研究论文

地址链接:《动手做科研》03. 如何阅读人工智能研究论文 导读: 在刚迈入科研时&#xff0c;人人都说读论文很重要&#xff0c;但是很少有人能完整地教你应该如何读论文。论文不仅揭示了行业的最新进展和趋势&#xff0c;而且为我们提供了改进技术和解决复杂问题的思路。然而&…

你知道缓存的这个问题到底把多少程序员坑惨了吗?

在现代系统中&#xff0c;缓存可以极大地提升性能&#xff0c;减少数据库的压力。 然而&#xff0c;一旦缓存和数据库的数据不一致&#xff0c;就会引发各种诡异的问题。 我们来看看几种常见的解决缓存与数据库不一致的方案&#xff0c;每种方案都有各自的优缺点 先更新缓存&…