『 Linux 』网络传输层 - TCP(二)

news2024/11/23 22:44:51

文章目录

    • TCP六个标志位
    • TCP的连接
      • 三次握手
    • 四次挥手
      • 为什么是三次握手和四次挥手
    • 重传机制

TCP六个标志位

在TCP协议报文的报头中存在一个用于标志TCP报文类型的标志位(不考虑保留标志位),这些标志位以比特位选项的方式存在,即对应标志位为0则表示为假,对应标志位为1则为真;

  • SYN

    用于建立连接,连接发起方发送SYN请求,表示希望发起一个连接,同步序列号;

  • ACK

    标识确认,该位被设置时,确认号字段有效,用于确认接收到的数据;

  • FIN

    用于关闭连接,一方发送FIN表示它已经完成数据发送并希望关闭连接;

  • RST

    用于重置连接,表示当前连接有问题,需要强制断开,通常用于错误或异常情况;

    RST报文被接收后需要重新进行三次握手来建立一个新的连接;

  • PSH

    推送数据,提示接收方应用程序应立即读取数据而不是在缓存中等待更多数据;

    本质上TCP也是一种生产者消费者模型的体现,其中发送方的用户层与接收方上层的用户层各担任了生产者和消费者的身份,其中发送方的用户层作为生产者,接收方的用户层作为消费者,当接收缓冲区满了后发送方再向接收方发出的数据流将被丢弃,在对于流量控制而言本质上就是在网络中的一种同步应用;

    PSH报文可以通过告诉接收方应尽快将这些数据流传给应用层避免数据长时间积累在接收缓冲区中导致接收方的接收缓冲区被写满;

  • URG

    表示紧急数据,紧急指针字段有效,用于标示紧急数据的位置,提示接收方优先处理;

    在操作系统中存在一个专门用于处理紧急数据的空间,当紧急数据被发送过后且URG标志位被设置,表示紧急指针有效,对应的紧急数据将会优先被处理;

    对于TCP而言,其数据流是按序到达的,所以为了不导致大面积的数据乱序,紧急指针所指向的紧急数据很小,通常只有一个字节;

    大部分情况下紧急数据用来处理或者检查对端接收缓冲区中数据长时间不被处理导致的发送方所发送的数据无法被接收方接收导致发送方未接收到应答等情况;

    可以将URG标志位理解为一个优先通道;

    可以通过系统调用接口send()设置对应的MSG_OOB选项来设置紧急数据,对应的也可通过系统调用接口recv()同样设置MSG_OOB选项来读取对应的紧急数据;

六个标志位中每一个标志位都标示着该TCP报文的类型,即一个TCP报文可能是多种类型,如在进行三次握手时,被握手方需要返回一个SYN+ACK的报文,其中该报文中的SYN表示也需要向对方建立起连接,而ACK表示的是对对方发起的SYN报文进行应答;

同时为了保证安全性,操作系统通常不会直接让用户直接修改对应的标志位,但对应的操作系统会为用户提供一些系统调用接口来间接修改报文的属性类型;

如当用户调用connect()系统调用接口向一个服务端发起连接时,本质上是让系统构建一个SYN类型的TCP报文并发送给对端;

对应的当一个已经连接的服务端或是客户端调用close()时本质上也是让系统在底层构建一个FIN类型的报文,并发送给对方表示希望断开该次连接;


TCP的连接

TCP是一个保证可靠传输的网络协议,其为了保证数据传输的可靠性,通常要与服务端建立起连接,但尽管TCP协议制定了若干的约定来保证数据在传输中的可靠性但也避免不了一些不可抗拒的因素;

本质上TCP协议保证可靠传输的前提是在与对端建立连接的前提下,保证未发生不可抗力异常时数据的传输(不可抗力异常通常为断电或设备故障,物理连接中断或是网络设备配置错误,任何一端应用层的崩溃等情况);

通常情况下服务器都是一对多的,即一台服务器将对应存在若干个客户端,当一台客户端向服务器发起连接请求时服务器中可能也在处理来自其他客户端的连接请求或是维护与其他客户端的连接,维护的方式同样的采用的是 “先描述后组织” ,无论是服务端还是客户端为保证连接的可靠性系统层面都要对已经建立好的连接创建一个对应的结构体,通过实例化结构体对象再以特定的数据结构将多个该结构体对象组织在一起,如链表;

对应的任何一端对连接的维护都是具有成本的,即需要花费时间和空间;

  • TCP允许连接建立失败

TCP所保证的可靠性是建立在已经建立连接的基础上,但实际上在建立连接时可能会因为多种因素导致连接建立失败,TCP能保证数据传输可靠但是无法保证在建立连接时能完全避免连接建立失败的情况;


三次握手

TCP协议建立连接时需要先进行三次握手;

所谓三次握手即为,请求建立连接方向对端发送SYN报文表示希望与该端建立连接,对端进行应答并告知也希望与该端建立连接返回一个SYN+ACK报文,请求方向对端返回ACK报文表示接收到对端的请求;

以该图为例:

  • Client向Server发送SYN报文
  • Server向Client返回SYN+ACK报文
  • Client向Server发送ACK报文

其中图中的每次报文发送的斜线表示每次报文的发送与接收具有时间差;

以客户端的视角而言,当客户端发送第三次握手的ACK报文后则表示该次握手已经建立成功,将会创建一个对应的结构体用于管理该连接;

而对于服务端而言,当其接收到第三次握手的ACK报文才表示该次连接真正被建立成功,才会生成对应的结构体对象来管理该连接,当服务端接收到三次握手中的最后一个ACK报文后不会再对该ACK报文进行应答,这也是 “应答不会再被进行应答” ;

即通常情况下对于客户端而言,当其认为连接已经建立成功后将会正常与服务端进行正常通信,若是服务端未接收到最后一个ACK报文就接收到了客户端的正常通行报文(数据流),服务端将会认为该连接并未建立成功,并不会接收该报文,而是向客户端发回一个RST报文告诉该连接并未建立成功,要求客户端重新发出最后一个ACK报文以要求建立连接;

这里也涉及到确认序号的问题,当发送端发出一个TCP报文给接收端,对应的接收端将对该报文向对端返回一个ACK报文表示应答,其中返回的ACK报文中的确认序号通常为 所接受报文序号+有效载荷大小 ,通常SYN标志位和FIN标志位将会占用一个序列号,所以对应的当服务器端接收到一个SYN报文时,假设该报文序列号大小为x,则服务端需要返回一个序列号大小为x+1SYN+ACK报文,示例为如下:

  • 第一次握手

    客户端发送一个SYN报文,假设序列号为x;

    Client -> Server : SYN, SEQ = x
    
  • 第二次握手

    服务器收到SYN报文,返回SYN+ACK报文,假设服务器的初始序列号为y;

    Server -> Client : SYN+ACK, SEQ = y, ACK = x+1
    
  • 第三次握手

    客户端收到SYN+ACK报文,返回ACK报文;

    Client -> Server: ACK, SEQ = x+1, ACK = y+1
    

当应用层想要该端与一个服务器端建立起连接,需要调用connect()系统调用接口使底层构建一个SYN报文,但实际上connect()只负责要求系统构建报文,其函数本身并不参与握手(只发起握手,不关心握手细节);

当一个执行流调用connect()系统调用接口使系统构建SYN报文后将进行阻塞,直到握手完成,当以客户端的视角第三次握手被发出后对应的连接将视为成功,对应的系统将为该连接维护对应的结构体,并且将该连接以套接字描述符的方式返回给connect()函数表示连接建立完成;

对应的当一个服务端需要获取一个来自客户端的连接时同样要调用accept()系统调用接口,同样的该接口不参与握手细节,当一个执行流调用该系统调用接口时对应的该执行流也会进入阻塞状态,直到三次握手完成并且连接被建立成功,对应的该被维护起来的连接将以套接字描述符的方式交给该函数作为返回值;


四次挥手

四次挥手是正常情况下连接断开的过程,通常为申请断开连接方调用系统调用接口close()让系统构建一个FIN报文并发送给对方;

四次挥手的过程为:

  • 第一次挥手

    发送方向接收方发送一个FIN报文表示希望与对端断开连接;

  • 第二次挥手

    接收方向发送方返回一个ACK报文表示接收到这个断开连接请求;

  • 第三次挥手

    接收方向发送方发送一个FIN报文表示希望与对端断开连接;

  • 第四次挥手

    发送方向接收方返回一个ACK报文表示也收到了这个断开连接请求,至此连接彻底断开;


为什么是三次握手和四次挥手

  • 为什么是三次握手

    三次握手是TCP为了保证双方通信时具有可靠性所定制的一种策略;

    而三次握手可以确保客户端和服务端至少都向对方发送了一次消息,从而确保连接建立的更为可靠;

    以朴素的角度来看三次握手实际上也可以被解析成四次握手;

    但为了提升连接创建的效率,TCP采用捎带应答的策略,在第二次握手中将ACK报文与SYN报文整合成了一个报文,即为SYN+ACK报文;

    在三次握手中能够确保双端都对对方进行一次消息的发送以及消息的接收来确保连接的稳定,因此三次握手中任何一次握手都不能少;

    假设三次握手的数量减少,连接的可靠性将大大降低,如以下几种情况:

    • 单次握手

      单次握手时通常为当客户端向服务端发起一个连接请求后服务端无法保证连接的可靠性就直接建立起对应的连接并进行维护,既不能保证客户端向服务端方向的数据传输是否可靠(服务端不进行应答即建立连接,不能保证服务端是否接收到对应的连接请求),也无法保证服务端向客户端方向数据传输是否可靠;

      同时维护连接通常是具有成本的,单次握手可能会导致同一个客户端向一个服务端大量发送连接请求,只要服务端一接收就建立起对应的连接并且对这些连接进行维护,将会大大占用服务端资源;

      一次握手服务端无法确认客户端的状态,无法保证连接的有效性和安全性;

    • 二次握手

      二次握手对于客户端而言,仍无法保证服务器已经准备好通信,二次握手通常意味着客户端发送SYN报文,服务端返回SYN+ACK报文,在未接收到客户端的ACK前服务器就已经认为连接已经成立,但实际上客户端收到SYN+ACK后可能由于种种原因无法进行数据传输,如网络中断等;

      而服务端将会为一个可能无效的连接预留资源,同样会面临无法确认客户端是否通信就绪的问题;

    三次握手将建立一个稳定可靠且能够确保全双工的通信连接,即任意一方都可以有效的进行发送数据和接收数据;

    通常情况下,客户端与服务端的关系通常是一对多的,即一个服务端对应着若干个客户端,而一次握手和二次握手两种方案最终都把负载交到了服务端身上,服务端随时都维护着一些无用资源,即并不进行通信了连接进行维护;

    三次握手可以将负担均匀的双方分配而不是只有单单服务端具有负担;

    同时一次握手和二次握手的方案将大大提升服务端受到SYN Flood(通过发送大量伪造的SYN报文,迫使服务器分配大量资源维护无效连接从而使其无法处理正常请求)等DoS攻击;

    同时三次握手不仅确保了连接的可靠性,三次握手时双方所发的报文也是一种协商报文,协商的包括双方的起始序号,确认序号位置,窗口大小等等;

    同时当任意一端发送RST报文后,表明当前连接被强行中断,任何已建立的连接状态信息都会被销毁,如果需要重新建立通信必须进行新的三次握手,以建立一个全新的TCP连接;

  • 为什么是四次挥手

    三次握手是建立通信连接的过程,而四次挥手是断开连接的过程,断开连接与建立连接是不同的,在连接建立过后数据是双向发送的,客户端和服务端任意一方都既扮演着发送方,也扮演者接收方的角色;

    当一端将数据发送完后准备关闭连接其无法确保对端是否还有数据未发完,所以断开连接的操作通常为四次挥手,即双方在确保没有数据要发送给对方时都要向对方发送连接关闭的请求;

    假设客户端主动向服务端发起断开连接的请求(客户端断开连接请求前的所有数据段已经发送完成),即客户端调用系统调用接close()时系统将生成一个FIN报文发送给对方并进入一个FIN_WAIT_1的状态,即第一次挥手;

    当服务端接收到FIN报文后将无条件进行ACK报文答复,即第二次挥手;

    此时连接并没有断开,只是客户端不再向服务端发送数据,对应的客户端将进入一个FIN_WAIT_2的状态,对应服务端也将进入一个CLOSE_WAIT的状态,这里客户端不发送数据表示不主动发送数据,对于数据的应答客户端还是会照常进行;

    在连接完全断开前也要保证数据传输的可靠,即当客户端一样可以接受来自服务端的数据并且处理对应数据;

    当服务端发送最后一条数据后服务端将主动向客户端发送一个FIN报文,即第三次握手;

    同时服务端能够确认自己没有数据需要再发送给客户端也能确认客户端没有数据再发送给本端,但是其无法保证客户端的数据已经全部处理完毕或是无法保证数据没有丢包,所以连接还是不能断开;

    若是数据段在网络中丢失或是出现其他情况时服务端需要启用重传策略;

    当客户端接收完并处理完所有数据段后将对服务端再次发送一个ACK报文表示确认服务端的连接断开请求;

    至此连接彻底关闭;


重传机制

为了保证数据传输时的可靠性,TCP定制了一系列的重传机制以避免数据丢失,常见的重传机制有快速重传,超时重传,选择性重传和快速恢复;

  • 快速重传

    快速重传用于发送方识别到所发数据丢失从而快速对数据进行重发;

    通常情况下快速重传机制将在接收方返回三个重复的ACK报文时被触发;

    假设发送方向接收方发送三个报文,对应报文的序列号为499,999,1499,将在下面情况发生快速重传;

    • 发送方发送三个报文段

      报文段1 : 序号499

      报文段2 : 序号999

      报文段3 : 序号1499

    • 接收方行为

      接收方接收到序号499报文,返回ACK报文,序号为500;

      接收方未接收到序号999报文,继续等待;

      接收方接收到序号1499报文,因为期望先收到序号999报文,因此发送重复序号为500ACK报文;

    • 发送方行为

      发送方收到第一个序号为500ACK报文,忽略;

      发送方收到第二个重复序号为500ACK报文,怀疑记录丢失,记录第二个重复ACK报文;

      发送方收到第三个序号为500ACK报文,触发重传机制;

    • 触发快速重传

      发送方立即重传丢失的报文段(序号为999);

  • 超时重传

    超时重传是TCP最基本的一种重传机制,通过定时器的方式来决定何时需要重传数据;

    其工作原理为:

    • 发送数据并启动定时器

      发送方再发送一个数据段后会启动一个定时器并记录下此数据段的序列号;

      定时器设置的超时时间通常是由 往返时间 和网络状态估算来的;

    • 等待确认

      发送方等待接收方响应回的ACK报文来确认已经成功接收到该段数据段;

      如果在定时器超时之前收到对应数据段的ACK报文则停止定时器并继续发送后续数据段;

    • 定时器超时并重传

      如果定时器到期时仍未收到对应报文的ACK应答,发送方将在新的定时器周期内重新发送该未经确认的数据段;

      超时时间一般采用 指数回退算法 来避免频繁重传所引起的网络拥塞;

  • 快速恢复

    快速回复机制通常与快速重传机制结合使用,当检测到丢失的数据段时,通过调整拥塞窗口以避免传输速率下降过多;

    • 快速重传后的拥塞控制

      当接收到三个重复的ACK报文并且执行了快速重传后,发送方将窗口大小减半并设置慢启动门限;

      具体来说 : ssthresh = cwnd/2 , 然后 cwnd = ssthresh + 3 * MSS;

    • 继续发送数据

      在快速恢复期间,发送方按照新的cwnd继续发送数据段而不进入漫长的慢启动过程;

      发送新的数据段是为了利用窗口中未消费的部分确保不浪费带宽;

    • 恢复正常传输

      当收到新的ACK报文后,将会把cwnd调整到适当的大小并恢复正常传输;

  • 选择性确认

    选择性确认也被称为SACK;

    可以告知发送方具体那些数据段已经被接收和丢失,前提是通信支持SACK机制;

    假设发送方发送三个报文段,序号分别为200,400(丢失),600;

    • 接收方发送SACK

      接收方接收到序号200的报文段,发送ACK201并附带SACK选项标记接受情况;

      接收方接收到序号600,发送ACK201并在SACK中标记已接收区间以及遗漏部分400-599;

    • 发送方根据SACK重传

      发送方根据SACK选项确认丢失的报文段(序号400-599)并仅重传这部分数据;

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

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

相关文章

VLAN虚拟局域网,eNSP实验讲解

VLAN虚拟局域网,eNSP实验讲解 一、概念二、eNSP仿真实验1、实验一:vlan演示(交换机端口access模式)2、实验二:vlan演示(交换机端口trunk模式) 一、概念 VLAN(Virtual Local Area Ne…

Ubuntu UFW防火墙规则与命令示例大全

在服务器安全领域,防火墙是守护网络安全的坚实盾牌。UFW(Uncomplicated Firewall),即“不复杂的防火墙”,是一个运行在iptables之上的防火墙配置工具,它为Ubuntu系统默认提供了一个简洁的命令行界面&#x…

基于 Python 的 Django 框架开发的电影推荐系统

项目简介:本项目是基于 Python 的 Django 框架开发的电影推荐系统,主要功能包括: 电影信息爬取:获取并更新电影数据。数据展示:提供电影数据的列表展示。推荐系统:基于协同过滤算法实现个性化推荐。用户系…

ORB-SLAM2源码学习:ORBextractor.cc:IC_Angle 利用灰度质心法求解关键点方向角

ORB特征点: 特征点是由关键点和描述子两部分组成,关键点是指特征点在图像中的位置,描述子是用来描述关键点周围的像素信息。ORB关键点是在FAST关键点的基础上进行改进给像素增加了一个主方向,称为Oriented FAST。描述子在BRIEF的…

【设计模式】如何用C++实现依赖倒置

【设计模式】如何用C实现依赖倒置 一、什么是依赖倒置? 依赖倒置原则(Dependency Inversion Principle,DIP)是SOLID面向对象设计原则中的一项。它的核心思想是: 高层模块不应该依赖于低层模块,两者都应该…

‌植物神经紊乱患者,这些锻炼适合你!

植物神经紊乱是一种常见的心理疾病,其主要症状包括焦虑、抑郁、失眠等,严重时还可能出现心慌、气短、憋气、出汗异常等症状。然而,通过适量的锻炼,我们可以帮助调节自主神经系统,缓解这些症状。那么,植物神…

Golang | Leetcode Golang题解之第525题连续数组

题目: 题解: func findMaxLength(nums []int) (maxLength int) {mp : map[int]int{0: -1}counter : 0for i, num : range nums {if num 1 {counter} else {counter--}if prevIndex, has : mp[counter]; has {maxLength max(maxLength, i-prevIndex)} …

第十七届山东省职业院校技能大赛通知分享

近日,山东省教育厅联合相关部门发布了关于举办第十七届山东省职业院校技能大赛的通知,标志着这一旨在深化教育教学改革、推进产教融合与校企合作的重要赛事即将拉开帷幕。 据了解,本次大赛将设中等职业教育组和高等职业教育组,共包…

Angular实现gridview效果

说明&#xff1a;使用angular实现grid效果&#xff0c;支持文字图片多条数据展示 效果图: step1: <mat-grid-list cols"2" rowHeight"2:1"><mat-grid-tile *ngFor"let course of courses">{{ course }}</mat-grid-tile> &l…

web of sicence使用教程(研究生版)

学习视频链接 进入web of science 通过校园资料库进入进入&#xff0c;选择如下 核心检索规则 不区分字母大小写逻辑运算符 可以通过括号改变优先级 常用通配符 短语检索 检索界面 检索类型 选择数据库

2-8软件包管理

8.1 配置仓库 1.配置本地仓库 #进行代码安装前需要先进行仓库配置和挂载 [rootlocalhost ~]# cd /etc/yum.repos.d [rootlocalhost yum.repos.d]# vim base.repo [baseos] namebaseos baseurl/mnt/BaseOS gpgcheck0 [appstream] nameappstream baseurl/mnt/AppStream gp…

适配器模式:类适配器与对象适配器

适配器模式是一种结构性设计模式&#xff0c;旨在将一个接口转换成客户端所期望的另一种接口。它通常用于解决由于接口不兼容而导致的类之间的通信问题。适配器模式主要有两种实现方式&#xff1a;类适配器和对象适配器。下面&#xff0c;我们将详细探讨这两种方式的优缺点及适…

性能测试:性能测试流程与方法

性能测试流程是指在进行性能测试时所遵循的一系列步骤和阶段&#xff0c;以确保对系统的全面测试和评估。性能测试流程的具体步骤可能会因组织、项目和测试需求而有所不同。 性能测试流程 分析现状&#xff1a;首先需要对应用程序或系统进行详细的分析&#xff0c;了解其当前的…

使用WebStorm开发Vue3项目

记录一下使用WebStorm开发Vu3项目时的配置 现在WebStorm可以个人免费使用啦&#xff01;&#x1f929; 基本配置 打包工具&#xff1a;Vite 前端框架&#xff1a;ElementPlus 开发语言&#xff1a;Vue3、TypeScript、Sass 代码检查&#xff1a;ESLint、Prettier IDE&#xf…

Java已死,大模型才是未来?

作者&#xff1a;不惑_ 引言 在数字技术的浪潮中&#xff0c;编程语言始终扮演着至关重要的角色。Java&#xff0c;自1995年诞生以来&#xff0c;便以其跨平台的特性和丰富的生态系统&#xff0c;成为了全球范围内开发者们最为青睐的编程语言之一 然而&#xff0c;随着技术的…

Allegro: 开源的高级视频生成模型

我们很高兴地宣布 Allegro 的开源发布&#xff0c;这是 Rhymes AI 先进的文本到视频模型。Allegro 是一款功能强大的人工智能工具&#xff0c;能将简单的文字提示转化为高质量的视频短片&#xff0c;为人工智能生成视频领域的创作者、开发者和研究人员开辟了新的可能性。我们希…

【OD-支持在线评测】智能驾驶(200分)

📎 在线评测链接 https://app5938.acapp.acwing.com.cn/contest/11/problem/OD1073 🍓 OJ题目截图 🍿 最新机试E卷,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 94 分 🌍 评测功能需要 ⇒ 订阅专栏 ⇐ 后私信联系解锁~ 文章目录 📎…

SpringBoot【实用篇】- 配置高级

文章目录 目标&#xff1a;1.ConfigurationProperties2.宽松绑定/松散绑定3. 常用计量单位绑定4.数据校验 目标&#xff1a; ConfigurationProperties宽松绑定/松散绑定常用计量单位绑定数据校验 1.ConfigurationProperties ConfigurationProperties 在学习yml的时候我们了解…

构造小练习

一。 二。 构造函数的调用顺序&#xff1a; 先走全局&#xff0c;再main函数&#xff0c;而局部静态的函数是走到它那里才开始初始化。所以先构造C&#xff0c;再A,B&#xff0c;最后D。 析构函数的顺序&#xff1a; 先析构局部的&#xff0c;再析构全局的。后定义的先析构。…

openapi回调地址请求不通过

目录 1. 验证url接口get请求本地自测报错 2. 测试回调模式成功不返回结果 3. 测试回调模式返回结果带双引号 对接企业微信 产生会话回调事件 接口问题解决 1. 验证url接口get请求本地自测报错 java.lang.IllegalArgumentException: Last encoded character (before the pa…