传输层之 TCP 协议

TCP协议段格式

        源/目的端口号:表示数据是从哪个进程来,到哪个进程去。

        序号:发送数据的序号。

        确认序号:应答报文的序号,用来回复发送方的。

        4 位首部长度:一个 TCP 报头,长度是可变的,不像 UDP 固定是 8 个字节。描述了 TCP 报头具体多长。因为选项之前的部分都是确定的 20 字节,所以首部长度 -20 字节就是选项部分的长度。如果首部长度值是 5,表示整个 TCP 报头是20字节(相当于没有选项)。因为 4bit => 0 - 15,所以 TCP 报头最长为 15 * 4 = 60 字节(选项相当于是 40 字节)。

        保留:占个位置,现在没用但是以后可能会用。如果 TCP 后续引入了一些新功能,就可以使用这些保留位字段。就像现在用 128G 内存的手机够用,但是建议 256G 或者更大,为了后续能有空间。

        URG:紧急指针是否有效

        ACK:确认号是否有效,如果标志位为 1,表示是应答报文,如果是 0,就表示不是

        PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走

        RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文

        SYN:请求建立连接;我们把携带SYN标识的称为同步报文段

        FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段

        检验和:发送端填充,CRC校验。接收端校验不通过,则认为数据有问题。此处的检验和不光包含TCP首部,也包含TCP数据部分。

TCP 内部核心工作机制

确认应答(安全机制)

        这是实现可靠传输最核心的机制。TCP 进行可靠性传输,最主要的就是靠这个确认应答机制。A 给 B 发了消息,B 收到之后就会返回一个 应答报文(ACK),此时 A 收到应答之后就知道数据已经顺利到达 B 了。

        但是,网络可能会出现“先发后至”的情况,即我给对方发了 吃饭做我女朋友 这两条信息,本来对方是 可以不行 的,但由于“先发后至”,我就会收到 不行可以,这时候就会对我造成信息的误解。 

为了解决上述问题,就可以给传输的数据和应答报文进行编号即可:

        每一个 ACK 都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据;下一次你从哪里开始发。

        应答报文报头中确认序号填写的是 1001,就是刚才 1000 字节的数据基础上 +1。表示的含义是:小于 1001 的数据已经确认收到了、接下来应该从 1001 这个序号开始继续发送数据了。如果 1001 这个 ACK 丢了,但是 2001 这个没丢,就会表示 2001 之前的数据都收到了。

        小结:TCP 具有可靠传输能力,最主要就是通过确认应答机制来保证的,通过应答报文,就可以让发送方知道数据是否传输成功;进一步地引入了序号和确认序号,针对多组数据进行详细区分。

超时重传

        在讨论确认应答的时候,都是建立在顺利传输的基础上,但如果传输过程丢包了呢?发的数据丢了、返回的 ACK 丢了或者还在路上,此时发送方没有收到 ACK,就会统一认为已经丢包了。此时 TCP 就引入了重传机制。

        主机 A 发送数据给 B 之后,可能因为网络拥堵等原因,数据无法到达主机 B。TCP 引入了一个 时间阈值,如果超过这个阈值也没有收到 ACK,此时就会认为已经是丢包了,就会重新传输。

        但如果是 应答报文丢了 或者 应答报文还在路上,此时 TCP 又重发了,那么就有可能出现接收到两个相同的数据。 TCP 针对这种重复的数据传输,可以进行特殊的处理进行去重:TCP 存在一个“接收缓冲区”这样的存储空间(每个 TCP 的 Scoket 对象,都有一个发送缓冲区和一个接收缓冲区),即接收方的操作系统内核里的一段内存。B 收到 A 的数据,其实就是 B 的网卡读到了数据,然后把这个数据放到 B 对应的接收缓冲区中。可以想象成是一个优先级阻塞队列,根据数据的序号很容易识别是否有数据重复,如果重复就把后来的那份数据丢弃。TCP 使用这个接收缓冲区对收到的数据按序号进行重新排序,保证应用程序 read 到的数据和发送的顺序一致。

        如果重传的数据又丢了的话,就会再一次重传,每次重传所需的时间间隔都会增加,当重传次数达到一定时,TCP认为网络或者对端主机出现异常,就会直接断开连接(避免浪费系统资源)。由于去重和重新排序机制的存在,发送方只要发现 ACK 没有按时到达,就会重新发送数据。

        小结:可靠传输是 TCP 最核心的部分。可靠传输是通过 确认应答 + 超时重传 来进行体现的。其中确认应答描述的是传输顺利的情况;超时重传描述的是传输出现问题的情况。这两者相互配合,共同支撑 TCP 整体的可靠性传输。

连接管理

        连接:TCP 建立连接,就是在 A 记录 B 的 IP和端口,在 B 记录 A 的 IP和端口,当这两部分信息都被维护好了之后,连接就有了。此时,也把保存这部分信息的空间(数据结构)也称为连接。断开连接就是 A 和 B 把自己储存的连接信息(数据结构)删了。

        管理:就是描述了连接如何创建(三次握手),如何断开(四次挥手)。

三次握手

        通信双方各自要记录对方的信息,彼此之间要相互认同。

        SYN:同步报文段,客户端主动给服务器端发起的建立连接请求。在 TCP 报文段第五位。(synchronize,同步)

三次握手重要的两个状态:

1. LISTEN:服务器的状态。表示当前服务器已经准备就绪,随时可以有客户端来建立连接。

2. ESTABLISHED:客户端和服务器端都有。表示建立完成,接下来可以正常通信了。

此时知道,彼此之间都是对方唯一的羊了之后就相当于确认恋爱关系了,即连接建立完毕。但现在可看到是进行了四次交互,是因为中间两次是可合并成一次的(节约资源)。

所谓的三次握手,本质上是进行了“四次”交互。通信双方各自要向对方发起一个“建立连接”的请求,同时双方都得回应对方一个 ACK。

        中间两次交互能合并的原因:封装分用两次,一定比封装分用一次成本要高。这几次交互过程都是纯内核完成的,即服务器系统内核收到 SYN 后,会立即发送 ACK 也会立即发送 SYN。就像在同一家网店下单购买两件商品,发两个快递肯定比直接发一个快递成本要高。

        如果是两次握手的话,不能完成建立连接得到过程。如果少了最后一次握手,那么对于 美羊羊 来说,不知道 喜羊羊 是不是她的唯一。

        三次握手还有一个重要的作用:可以验证通信双方各自的 发送能力和接收能力 是否正常。 因此,三次握手也一定程度上保证了 TCP 传输的可靠性(只是辅助作用)。

三次握手的意义:

1. 让通信双方各自建立对对方的“认同”(保存对方的信息)

2. 验证通信双方各自的发送能力和接受能力是否 OK

3. 在握手的过程中,双方协商一些重要参数(TCP 通信过程中,有些数据通信双方需要相互同步,此时就需要有这样的交互过程)

四次挥手

        和三次握手类似。通信双方各自向对方发起一个断开连接的请求,再各自给对方一个回应。

四次挥手重要的两个状态:

1. CLOSE_WAIT:等待关闭,等待调用 close 方法关闭 Soclet。出现在被动发起断开连接的一方。建立连接一定是客户端主动发起请求的。断开连接可能是客户端注定发起,也可能是服务器注定发起。

2. TIME_WAIT:出现在主动发起断开连接的一方。如上图,在左边客户端的视角,当发完 ACK 的时候就会认为四次挥手已经完成了,就会断开连接。但忽视了一个问题:如果 ACK 丢包了,那么在右边服务器的视角就不知道是 ACK 丢了还是自己的 FIN 没发过去。此时右边服务器就会触发超时重传机制,再发一个 FIN。所以 TIME_WAIT 存在的意义就是解决这一情况,会保持 2MSL 这么长时间,MSL 表示在互联网上,两个节点之间数据传输消耗的最大时间,超过这个时间如果没收到重传的 FIN,就默认 ACK 已经到达,此时就断开连接(如果恰好 ACK 丢了,又恰好重传的 FIN 也丢了,那就没办法了)。只有 TIME_WAIT 是等 2MSL,其他的过程都是根据超时重传的阈值。

此时连接就断开了,就从情侣转变为路人。

这里是四次的原因是:FIN 是由应用程序触发的;ACK 是由内核控制的,在收到 FIN 之后会立即返回 ACK,因此应用程序再发送 FIN 的时候就会存在一个时间差,就不能合并成一个了。除非在代码实现上,ACK 和 FIN 之间的时间间隔比较短,此时就有可能合并成一个。(就像我今天买了个快递,过了一周又买了个)

        小结:TCP 作为一个有连接的协议,就需要建立连接和断开连接。其中建立连接的过程是三次握手,断开连接的过程是四次挥手。

滑动窗口

        对于每一个发送的数据段,都要给一个ACK确认应答,然后收到ACK后再发送下一个数据段。这样做有一个比较大的缺点,就是性能较差。尤其是数据往返的时间较长的时候。

        因为可靠性和传输效率本身是矛盾的,所以在保证可靠性的基础上来尽可能提高传输效率,尽量降低效率的折损(其实是将多个段的等待时间重叠在一起了)。 

滑动窗口的本质就是批量发送一组数据。我们把无需等待确认应答而可以继续发送数据的最大值叫做窗口大小,上图的窗口大小是 4000。只要有一个 ACK 到了,就可以继续发送下一条数据了,不必等四个 ACK 都到。(就像去饭馆吃饭,有座位就能去,不用等所有人都吃完)

 此时如果出现了丢包,如何进行重传?这里分两种情况讨论。

一、ACK 丢了

        这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认,因为有确认序号的设定。所以就引申出两个概念:ACK 并不是所有都发的,有时候会少发一部分(并不影响可靠性,同时节省系统资源);如果所有的 ACK 都恰好丢了,那么就会认为网络已经出现严重故障了。

二、数据丢了

        由于 1001-2000 字节的数据丢包了,接下来的 2001-3000 到达主机 B 之后,B 返回给 A 的ACK 确认序号仍然是 1001,意思是在索要从 1001 开头的数据。当 1001-2000 这个数据重传被收到之后,因为后面的 2001-7000 原本都以正常到达,被放到了接收端操作系统内核的接收缓冲区中,所以 ACK 返回序号就是 7001。对于这个丢包重传的方式,叫做“快速重传”,这个可以视为是 超时重传机制 在滑动窗口下的变形。

        因此可以得出结论:如果当前数据传输密集,按照滑动窗口方式传输,此时按照快速重传机制;如果当前数据传输稀疏,不再按照滑动窗口方式传输,此时还是按照超时重传机制传输。

流量控制

        这是一种干预窗口大小的机制。滑动窗口,窗口越大,传输效率就越高,但是窗口不能无限大:完全不等 ACK,就没有可靠性而言;窗口太大会消耗大量系统资源;发送速度太快接收方处理不过来等于白发。因此接收方的处理能力是一个重要的约束依据,发送方的速度不能超出接收方的能力。

        我们使用接收方接收缓冲区的剩余大小来衡量接收方的处理能力(剩的越多说明处理能力越快)。所以每次 A 给 B 发送数据,B 都要算一下剩余空间,然后把这个值通过 ACK 报文返回给 A,A 就会根据这个值来决定接下来发送的窗口大小是多少。

        虽然 TCP 报文结构的窗口大小是 16 位,但并不意味最大是 64K,因为在选项部分,引入了窗口扩展因子:比如窗口大小已经是 64K,扩展因子里面写了个 2,意思就是让 64K << 2,即左移两位就变成了 256K。

        由于接收方缓冲区剩余空间是一直动态变化的,所以每次返回 ACK 所带的窗口大小都在变化,因此发送方也会进行动态调整。当窗口大小为 0 的时候,发送方就会暂停发送,在这期间会定期给 B 发送 窗口探测报文,只是起到出发 ACK 从而查询窗口大小的功能,不携带具体数据。

拥塞控制

        流量控制和拥塞控制共同决定发送方的窗口大小是多少。只不过流量控制考虑的是接收方的处理能力;而拥塞控制描述的是传输过程中,中间节点(路由器 / 交换机)的处理能力。但是由于中间节点不好衡量,因为存在太多变数(路径、数据多少),因此就通过“实践”的方式来测试出一个合适的值。(就像 A 不停挑逗 B,步步逼近,看看 B 什么时候发火)

        当增长速率达到阈值(ssthresh),就从指数增长变成了线性增长。增长的前提是不丢包,如果传输的过程中丢包了,说明此时发送的速率已经接近网络的极限了,就会把窗口大小重新开始调整。因此可以知道:拥塞窗口不是固定的数值,而是一直动态变化的,随着时间的推移逐渐达到一个动态平衡的过程。这样既能把问题解决也能随着网络的变化而变化。

        拥塞窗口和流量控制的窗口,共同决定了发送方实际的发送窗口。

延时应答

        也是与滑动窗口有关的。因为滑动窗口的窗口大一点,传输速度就快一点,因此要在接收方能够处理得了的前提下,尽可能把窗口变大一些。延时:就是收到数据之后,不会立即返回 ACK,而是稍微等一会,在等的时间里,接收方的应用程序会把缓冲区 的数据消费一波,此时返回的剩余空间就变大了。(就是上面说到的不用每一条都发)

捎带应答

        是在延迟应答的基础上,引入的捎带应答。很多情况下,客户端服务器在应用层都是 "一发一收" 的,即业务上的请求和响应。

面向字节流

创建一个TCP的socket,同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区:

        调用write时,数据会先写入发送缓冲区中;

        如果发送的字节数太长,会被拆分成多个TCP的数据包发出;

        如果发送的字节数太短,就会先在缓冲区里等待,等到缓冲区长度差不多了,或者其他合适 的时机发送出去;

        接收数据的时候,数据也是从网卡驱动程序到达内核的接收缓冲区; 然后应用程序可以调用read从接收缓冲区拿数据;

        另一方面,TCP的一个连接,既有发送缓冲区,也有接收缓冲区,那么对于这一个连接,既可以读数据,也可以写数据。这个概念叫做 全双工。

由于缓冲区的存在,TCP程序的读和写不需要一一匹配,例如:

        写100个字节数据时,可以调用一次write写100个字节,也可以调用100次write,每次写一    个字节;

        读100个字节数据时,也完全不需要考虑写的时候是怎么写的,既可以一次read   100个字节,也可以一次read一个字节,重复100次。

粘包问题

        接收缓冲区是把收到的多个数据都得放到一起,就像是都粘在一起了,此时就会出现一个问题:应用程序在进行 read 的时候,怎么知道都到哪里就算是一个完整的应用层数据包呢?

        为了解决粘包问题,解决方案就是约定好应用层协议,明确应用层数据包之间的边界即可。比如:约定好分隔符;约定好每个包的长度。

TCP 异常情况

        在传输过程中出现了不可抗力。

一、程序崩溃或主机关机

        主机关机是要先杀进程然后才正式关机。进程没了,对应的 PCB 就没了,对应的文件描述符表就释放了,相当于 Socket.close(),此时内核会继续完成四次挥手,即使可能没挥完也任然是一个正常断开的流程。

二、主机掉电或网线断开

        接收方掉电:发送方仍然在继续发数据,但是一直等不到 ACK,就会触发超时重传,但重传几次后依旧没收到,就会尝试重置 TCP 连接,显然也会失败,因此就会单方面放弃连接。

        发送方断电:接收方发现过了很久都没数据来,不知道是还没发还是发送方已经挂了,然后接收方就会周期性给发送方发送一个信息,确认对方是否还正常工作。这个也被称作是“保活机制”,发送的消息也被称为“心跳包”,这是用来确认通信双方是否处于正常的工作状态中。

TCP 和 UDP 的对比

        TCP 优势:可靠传输。绝大部分场景中,都需要可靠传输的时候。

        UDP 优势:效率更高。有些场景对于性能要求更苛刻的时候(例如同一个机房内服务器之间的网络通信)。同时,UDP 天然支持广播。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32学习和实践笔记(25):USART(通用同步、异步收发器)

一&#xff0c;STM32的USART简介 USART即通用同步、异步收发器&#xff0c;它能够灵活地与外部设备进行全双工数据交换&#xff0c;满足外部设备对工业标准 NRZ 异步串行数据格式的要求。 UART即通用异步收发器&#xff0c;它是在USART基础上裁剪掉了同步通信功能。 开发板上…

【Web】CTFSHOW 七夕杯 题解

目录 web签到 easy_calc easy_cmd web签到 CTF中字符长度限制下的命令执行 rce(7字符5字符4字符)汇总_ctf中字符长度限制下的命令执行 5个字符-CSDN博客7长度限制直接梭了 也可以打临时文件RCE import requestsurl "http://4ae13f1e-8e42-4afa-a6a6-1076acd08211.c…

Vision Mamba:高效视觉表示学习双向状态空间模型,超越Vision Transformer!

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; Vision Mamba: Efficient Visual Representation Learning with Bidirectional State Space Model 引言&#xff1a;探索视觉领域的新方向 在计算机视觉领域&…

翻工第二次 Ant Design Pro 下载,发现问题,电脑网络配置有误,魔法了

一、相关网址链接 鱼皮的用户中心项目 &#xff08;前端Ant Design Pro构建&#xff09; 语雀 ## 没有选择umi版本这一步 Issue #11144 ant-design/ant-design-pro GitHub 关于umi ui图标未显示问题_umi ui不出现-CSDN博客 二、存在问题 导致下载速度慢 本人镜像代码写…

双向链表(详解)

在单链表专题中我们提到链表的分类&#xff0c;其中提到了带头双向循环链表&#xff0c;今天小编将详细讲下双向链表。 话不多说&#xff0c;直接上货。 1.双向链表的结构 带头双向循环链表 注意 这几的“带头”跟前面我们说的“头节点”是两个概念&#xff0c;实际前面的在…

第十三届蓝桥杯决赛(国赛)真题 Java A 组【原卷】

文章目录 发现宝藏【考生须知】试题 A: 火柴棒数字试题 B: 小蓝与钥匙试题 C: 内存空间试题 D: 斐波那契数组试题 E: 交通信号试题 F: 数组个数试题 G: 六六大顺试题 H : \mathrm{H}: H: 选素数试题 I: 图书借阅试题 J \mathrm{J} J : 括号序列树 发现宝藏 前些天发现了一个…

数据分析:基于sparcc的co-occurrence网络

介绍 Sparcc是基于16s或metagenomics数据等计算组成数据之间关联关系的算法。通常使用count matrix数据。 安装Sparcc软件 git clone gitgithub.com:JCSzamosi/SparCC3.git export PATH/path/SparCC3:$PATHwhich SparCC.py导入数据 注&#xff1a;使用rarefy抽平的count ma…

stm32单片机学习路线

第一步 编程及硬件基础知识 1.掌握C语言基础 作为STM32的主要编程语言&#xff0c;C语言的基础知识是必不可少的。建议通过书籍、在线课程或者教学视频系统地学习C语言的基础知识&#xff0c;包括语法、数据类型、函数、指针等。 2.了解电子电路基础 对于单片机开发来说&…

经开区创维汽车车辆交接仪式顺利举行,守护绿色出行助力低碳发展

5月10日&#xff0c;“创维新能源汽车进机关”交车仪式于徐州顺利举行&#xff0c;20辆创维EV6 II正式交付经开区政府投入使用。经开区陈琳副书记、党政办公室副主任张驰主任、经开区公车管理平台苑忠民科长、创维汽车总裁、联合创始人吴龙八先生、创维汽车营销公司总经理饶总先…

OpenHarmony 实战开发——移植通信子系统

通信子系统目前涉及Wi-Fi和蓝牙适配&#xff0c;厂商应当根据芯片自身情况进行适配。 移植指导 Wi-Fi编译文件内容如下&#xff1a; 路径&#xff1a;“foundation/communication/wifi_lite/BUILD.gn” group("wifi") {deps [ "$ohos_board_adapter_dir/ha…

asp.net mvc使用IHttpModule拦截所有请求,包括资源文件

目录 HttpApplication 类 添加App_Code文件夹 MyHttpModel2 Web.config添加配置&#xff0c;在iis模块中生效 项目发布后&#xff0c;察看注册的自定义模块 框架集&#xff1a;.NET Framework 4.7web框架&#xff1a;asp.net mvc 5 HttpApplication 类 HttpApplication 类…

数据库备份与恢复--06---MySQL集群高可用架构之MHA

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 MySQL集群高可用架构之MHA1.什么是MHAMHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件 &#xff0c;m…

2024最新洗地机选购攻略!分享四款热门洗地机推荐

洗地机可以说是现代家庭生活中一大利器&#xff0c;它能帮我们快速搞定家里的地板清洁工作&#xff0c;省去了自己清洗滚刷的麻烦。不过&#xff0c;当下市面上洗地机品牌种类繁多&#xff0c;价格区间也相差悬殊&#xff0c;要选择一款性价比较高、使用体验较好的洗地机产品&a…

太阳能无人机的多元化应用

随着新能源技术的不断发展和成熟&#xff0c;太阳能在无人机的应用技术已经成熟。太阳能无人机得到了量产和广泛的应用。传统无人机相比&#xff0c;太阳能无人机无需燃油&#xff0c;运行费用低廉&#xff0c;搭载多种高科技设备&#xff0c;能够高效、多元化地采集和分析各类…

AI算法-高数3-导数-求导法则

P16 2.2 求导法则&#xff0c;宋浩老师&#xff1a;2.2 求导法则_哔哩哔哩_bilibili 反函数求导法则&#xff1a; 复合函数求导&#xff1a;剥洋葱法。

蜂群优化算法(bee colony optimization algorithm)

​注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 算法引言 自然界的启发&#xff1a;BSO算法的灵感来自于蜜蜂在自然界中的觅食行为。在自然界中&#xff0c;蜜蜂需要找到花蜜来生存。当一只蜜…

在做题中学习(53):寻找旋转数组中的最小值

153. 寻找旋转排序数组中的最小值 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;O(logn)->很可能就是二分查找 思路&#xff1a;再看看题目要求&#xff0c;可以画出旋转之后数组中元素的大小关系&#xff1a; 首先&#xff0c;数组是具有二段性的(适配二分查…

车载测试系列:UDS诊断服务

UDS诊断服务介绍 UDS&#xff08;Unified Diagnostic Services&#xff0c;统一诊断服务&#xff09;诊断协议诊断测试仪和ECU之间一种通信协议&#xff0c;在ISO14229中规定。UDS被用在几乎所有由OEM一级供应商所制造的新ECU。 诊断工具与车内的所有ECU均有连接&#xff0c;…

IO 5.10

在一个进程中&#xff0c;创建一个子线程。 主线程负责&#xff1a;向文件中写入数据 子线程负责&#xff1a;从文件中读取数据 要求使用线程的同步逻辑&#xff0c;保证一定在主线程向文件中写入数据成功之后&#xff0c;子线程才开始运行&#xff0c;去读取文件中的数据#incl…

bash: docker-compose: 未找到命令

bash: docker-compose: 未找到命令 在一台新的服务器上使用 docker-compose 命令时&#xff0c;报错说 docker-compose 命令找不到&#xff0c;在网上试了一些安装方法&#xff0c;良莠不齐&#xff0c;所以在这块整理一下&#xff0c;如何正确快速的安装 docker-compose cd…
最新文章