Linux网络编程(四-TCP协议)

目录

一、TCP概念

二、TCP的首部格式

三、TCP可靠传输机制

3.1 确认应答机制

3.2 超时重传机制 

3.3 连接管理 

3.3.1 三次握手

3.3.2 四次挥手

3.4 流量控制 

3.5 拥塞控制

四、TCP效率机制

4.1 滑动窗口 

4.2 重发控制 

4.3 延迟应答 

4.4 捎带应答

五、TCP的异常情况处理 

六、TCP协议特点总结


一、TCP概念

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接(连接导向)的、可靠的、 基于IP的传输层协议。TCP协议属于OSI七层模型中的传输层

二、TCP的首部格式

TCP协议段分为首部用户数据部分,TCP协议段结构如图所示:

TCP首部不包括选项为固定20字节

  • 源端口号:表示发送端端口号,字段长16位。
  • 目的端口号:表示接收端端口号,字段长16位。
  • 序号:表示发送数据的位置,每发送一次数据,就累加一次该数据字节数的大小。注意:序号不会从0或1开始,而是在建立连接时由计算机生成的随机数作为其初始值,通过SYN包传给接收端主机。然后再将每转发过去的字节数累加到初始值上表示数据的位置。此外,在建立连接和断开连接时发送的SYN包和FIN包虽然并不携带数据,但是也会作为一个字节增加对应的序号,字段长32位。
  • 确认序号:用于给对方的响应,值为收到TCP报文段的序号值加1(表示当前的应答报文针对的是哪个消息进行的确认应答),发送端收到这个确认序号以后可以认为在这个序号之前的所有数据都已经被正常接收,字段长32位。
  • 4位首部长度:表示TCP首部的长度,字段长4位,单位为4字节,所以该字段能表示的长度范围为[0,60]字节,而不包括选项的首部长度固定为20字节,所以该字段真实的取值范围为[5,15] × 4字节为[20,60]字节,二进制表示为[0101,1111]。
  • 6个标志位:
    • URG:紧急标志位,配合16为紧急指针使用。
    • ACK:确认应答标志位,凡是报文具有应答特性,该标志位就会被设置为1。
    • PSH:用于提示接收端应用程序立刻从TCP缓冲区将数据取走。
    • RST:用于重新建立连接,RST为1时,TCP必须强制断开连接,在重新建立连接。
    • SYN:用于建立连接,SYN为1时,表示希望建立连接。
    • FIN:用于断开连接,FIN为1时,表示今后不会再有数据发送,希望断开连接。
  • 窗口大小:进行流量窗口控制,字段长16位。
  • 校验和:发送端填充,CRC校验,接收端校验不通过,则认为数据有问题,此处的检验和不光包含TCP首部,也包含TCP数据部分,字段长16位。
  • 紧急指针:标识那部分数据时紧急数据,字段长16位。

三、TCP可靠传输机制

3.1 确认应答机制

在TCP中,当发送端的数据到达接收主机时,接收端主机会返回一个已收到消息的通知,这个消息叫做确认应答(ACK)。 

TCP通过确认应答(ACK)机制实现可靠的数据传输,当发送端将数据发出之后会等待对端的确认应答,如果有确认应答则说明数据已经成功达到对端,反之,则数据大概率丢失。 

TCP将每个字节的数据都进行了编号,即为序列号(序号)

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

3.2 超时重传机制 

发送端在一定时间内没有收到确认应答,发送端就认为数据已经丢失,并进行重发。由此,即使产生了丢失,仍然能够保证数据能够到达对端,实现可靠传输,这就是超时重传机制

主机A发送数据给主机B之后,可能因为网络拥堵等原因导致数据丢失无法到达主机B。此时,如果主机A在一个特定的时间间隔内都未收到主机B发来的确认应答(ACK),则会将该数据进行重发。

未收到确认应答并不意味着数据一定丢失,也有可能是确认应答(ACK)丢失,这种情况也会导致发送端因没有收到确认应答(ACK)而进行重发。上图中,主机A因未收到主机B的确认应答(ACK),而对数据进行了重发,主机B其实已经收到了两次1~1000的数据,再收到第二次1~1000的数据时,主机B会根据序列号来进行去重。(接收的数据会放在操作系统内核的接收缓冲区中,接收缓冲区可以视为是一个阻塞队列,对于收到的数据,TCP会根据序号检查这个数据是不是在缓冲区中已经存在,如果存在则丢弃,如果不存在则放进去)

3.3 连接管理 

在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接。 

3.3.1 三次握手

过程:

  1. 客户端向服务器端发送连接请求(SYN),申请建立客户端到服务器端的连接。
  2. 服务器端返回确认应答(ACK)(第一次SYN的应答)和连接请求(SYN),申请建立服务器端到客户端的连接。
  3. 客户端收到数据,状态置为ESTABLISHED,表示客户端到服务器端连接建立完成,并且发送确认应答(ACK)(第二次SYN的应答),服务器端收到数据,状态置为ESTABLISHED,表示服务器端到客户端的连接建立完成。

服务器端状态转化:

  • [CLOSED -> LISTEN]:服务器端调用listen函数后进入监听状态,等待客户端连接。
  • [LISTEN -> SYN_RCVD]:一旦监听到连接请求(SYN),就将该连接放入内核等待队列中,并向客户端发送ACK+SYN,应答并请求建立连接。
  • [SYN_RCVD -> ESTABLISHED]:服务器端一旦收到客户端的确认应答(ACK),就进入ESTABLISHED状态,表示连接建立完成,可以进行数据传输。

客户端状态转化:

  • [CLOSE -> SYN_SENT]:客户端调用connet函数,向服务器端发起连接请求(SYN)。
  • [SYN_SENT -> ESTABLISHED]:收到服务器端的确认应答(ACK),connect函数调用成功,进入ESTABLISHED状态,表示连接建立完成,可以进行数据传输。
3.3.2 四次挥手

过程:

  1. 客户端发送FIN到服务器端,申请关闭客户端到服务器端的连接。
  2. 服务器端收到FIN状态置为CLOSE_WAIT,并返回确认应答(ACK)。(这个动作是系统实现TCP协议栈默认执行的,不需要程序来调用代码)
  3. 服务器端发送FIN到客户端,申请关闭服务端到客户端的连接。(程序手动调用close函数)
  4. 客户端收到FIN返回确认应答(ACK),并进入TIME_WAIT时间等待状态,客户端等待一段时间后,状态置为CLOSED,表示已经关闭连接。服务器端收到确认应答(ACK)后,状态置为CLOSED,表示已经关闭连接。

服务器端状态转化:

  • [ESTABLISHED -> CLOSE_WAIT]:当客户端主动关闭连接(调用close),服务器端会收到结束报文段(FIN),服务器返回确认应答(ACK),进入CLOSE_WAIT状态。
  • [CLOSE_WAIT -> LAST_ACK]:进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据)。当服务器端真正调用close关闭连接时,会向客户端发送FIN,此时服务器进入LAST_ACK状态,等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)。
  • [LAST_ACK -> CLOSE]:服务器端收到FIN的确认应答(ACK),进入CLOSE状态,彻底关闭连接。

客户端状态转化:

  • [ESTABLISHED -> FIN_WAIT_1]:客户端主动调用close时, 向服务器端发送结束报文段(FIN), 同时进入FIN_WAIT_1;
  • [FIN_WAIT_1 -> FIN_WAIT_2]:客户端收到服务器对结束报文段的确认应答(ACK), 则进入FIN_WAIT_2,开始等待服务器的结束报文段(FIN)。
  • [FIN_WAIT_2 -> TIME_WAIT]:客户端收到服务器发来的结束报文段(FIN), 进入TIME_WAIT状态,向服务器端发送结束报文段(FIN)的确认应答(ACK)。
  • [TIME_WAIT -> CLOSED]:客户端要等待一个2MSL(Max Segment Life,报文最大生存时间)的时间,才会进入CLOSED状态,此时彻底关闭连接。

常见问题: 

  • 为什么服务端不将ACK和FIN合并一起发送,形成三次挥手呢?

答:ACK和FIN的发送时机不同,ACK是操作系统内核响应的(立即执行),FIN是需要由用户程序调用close函数才会发送,用户调用close函数的时间和内核响应的时间不同。

  • 为什么客户端要等待一段时间状态才置为CLOSED,而不直接将状态置为CLOSED?

答:如果客户端发给服务器端最后一个确认应答(ACK)丢失,此时,服务器端会重新给客户端发送结束报文段(FIN),如果直接置为CLOSE状态,则接收不到客户端重新发送结束报文段(FIN),从而导致无法重发确认应答(ACK),使服务器端无法进入CLOSED状态。

3.4 流量控制 

接收端处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。

因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制(Flow Control)

  • 接收端将自己剩余缓冲区大小存入TCP协议段首部中的“16位窗口大小”字段 ,通过确认应答(ACK)通知发送端,窗口大小越大,说明接收端的接收能力越强。
  • 发送端根据接收到这个窗口的大小,控制自己的发送速度。
  • 如果接收缓冲区满了,就会将窗口大小设置为0,这时,发送端不再发送数据,而是定期的发送一个窗口探测报文(只是为了知道窗口的大小),让接收端将窗口大小告诉发送端。

3.5 拥塞控制

TCP通过滑动窗口能够高效可靠的发送大量的数据,但是如果在刚开始阶段就发送大量的数据,可能会引发其他问题,一般来说,计算机网络都处在一个共享的环境,在网络出现拥堵时,突然发送一个较大量的数据,极有可能导致整个网络的瘫痪。 

TCP为了防止该问题的出现,引入慢启动机制,对发送数据量进行控制。 这里引入拥塞窗口,刚开始时,拥塞窗口设置为1,每收到一个确认应答(ACK)时,拥塞窗口加1,每次发送数据的时候,拥塞窗口和流量窗口的较小的值作为实际发送的窗口,即滑动窗口的大小。

拥塞窗口的增长速度是指数级别的,增长速度非常的快,为了控制增长速度,引入了一个叫做慢启动的阈值,当拥塞窗口超过这个阈值时,不再按照指数方式增长,而变为线性增长。

  • 当TCP开始启动的时候, 慢启动阈值等于窗口最大值。
  • 在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1。

四、TCP效率机制

4.1 滑动窗口 

由于TCP的确认应答机制存在,导致对每一个发送的数据段都要返回确认应答(ACK),收到确认应答(ACK)后,再发送下一个数据段,这样的传输方式产生了一个缺点,那就是,数据往返时间越长通信性能就越低。 

           

为解决这个问题,TCP引入了窗口这个概念,即使再往返时间较长的情况下,它也能够控制网络性能的下降,如上图所示,确认应答不再是单个数据段进行应答,而是以多个数据段进行应答,这个多个数据段的值由窗口大小控制,图中的窗口大小为4000个字节(四个数据段),发送前四个数据段的时候,不需要等待任何确认应答(ACK),直接发送。 

 

滑动窗口存在于发送端的发送缓冲区中,属于发送端的发送缓冲区的一部分

  • 滑动窗口中的数据段因其某种原因已在传输中丢失,发送端未收到此数据段的确认应答(ACK),此时滑动窗口保持不变,滑动窗口中数据段进行超时重传。
  • 滑动窗口以外的左边是已发送且收到应答的数据,右边是尚未发送的数据。
  • 滑动窗口中的数据段发送后,若如期收到确认应答(ACK),滑动窗口将会滑动到确认应答(ACK)中的序列号的位置,原先的数据段就可以不用进行重发,此时数据段就可以从滑动窗口中清除,滑动窗口整体向右滑动。
  • 滑动窗口的大小为min(流量窗口的大小,拥塞窗口的大小)

  • 滑动窗口本质为:指针或数组下标(暂且认为),int win_start、int win_end
  • 滑动窗口可以为0吗?答:可以,win_end由确认应答(ACK)中的16为窗口大小决定,当接收缓冲区慢的时候,窗口大小就会被设置为0,此时滑动窗口大小就为0。
  • 如果没有收到开始的报文的确认应答,而收到中间的影响吗?答:不影响
  • 滑动窗口如果一直向右移动会越界吗?答:不会,发送缓冲区为环形

4.2 重发控制 

滑动窗口传输数据过程中出现丢包,如何进行重传?

情况一:数据包已经抵达,确认应答(ACK)丢失 

这种情况下,不是确认应答(ACK)丢失不要紧,可以通过后续的确认应答(ACK)进行确认,确认应答(ACK)中确认序号的含义为确认序号前的所有序号都已经全部收到。 

情况二:数据包丢了 

  • 当1001~2000这段报文丢失后,发送端一直会收到1001这样的确认应答(ACK)。
  • 如果发送端主机连续三次收到相同的确认应答(ACK)如1001应答,那发送端主机就会重新发送1001~2000数据,此时,接收端收到1001~2000数据后,再次返回的确认应答(ACK)就是7001了,因为2001~7000数据都已经接收到了,被放到接收端操作系统内核的接收缓冲区中。

这种机制,即时不超时也会发生重传,称作“ 高速重发控制 ”也叫“ 快重传机制 ”。 

4.3 延迟应答 

接收数据的主机如果每次都立刻回复确认应答(ACK)的话,可能会返回一个较小的流量窗口,但是流量窗口越大,网络吞吐量越大,传输效率就越高,所以等待一部分时间,待接收端处理完一部分数据 ,就可以将流量窗口设置为大一点的值,这样网咯吞吐量大,效率高。

延迟是为了高吞吐量,但是也不能无限延迟,

  • 数量限制,每隔n个包就应答一次
  • 时间限制,超过最大延迟时间,就应答一次

具体的数量和时间,不同操作系统有差异,一般n取2,超时时间取200ms。

4.4 捎带应答

在延迟应答的基础上,我们发现,很多情况下,客户端服务器在应用层也是 "一发一收" 的,这意味着,TCP的确认应答(ACK)和回执数据可以通过一个包发送,这种方法就是捎带应答,通过这种机制可以使收发的数据量减少。需要注意:捎带应答需要依赖延迟应答

五、TCP的异常情况处理 

  • 进程终止:进程终止会释放文件描述符,仍然可以发送FIN,和正常关闭没有什么区别。
  • 机器重启:和进程终止的情况相同
  • 机器掉电/网线断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了就会进行reset,即使没有写入操作,TCP自己也内置了一个保活定时器,会定期询问对方是否还在,如果对方不在,也会把连接释放。

六、TCP协议特点总结

  • 有连接:通过三次握手建立连接后才可接发数据。
  • 可靠传输:网络数据传输是一跳一跳的,经过路途中的设备可能发生数据丢失,可靠传输是可能发生数据丢失但有机制保证对方能接收到。
  • 面向字节流:可以多次的收发数据(连接没有关闭时,可以多次的接收和发送数据)
  • 有接收缓冲区和发送缓冲区:发送数据时,是先写到发送缓冲区,再刷新缓冲区(flush)
  • 大小不受限制:多次的收发数据,每次的数据可以很大

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用观测云实现 Kubernetes 多集群可观测

简介 观测云的工作空间接入多个 Kubernetes 集群时,是如何区分不同集群,达到多集群的可观测性? 增加Tag NAMESPACE:DataKit 选举空间,需要设置 ENV_NAMESPACE 环境变量,值为非空字符,不同集群…

第三百七十回

文章目录 1. 概念介绍2. 使用方法2.1 获取所有时区2.2 转换时区时间 3. 示例代码4. 内容总结 我们在上一章回中介绍了"分享一些好的Flutter站点"相关的内容,本章回中将介绍timezone包.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

力扣递归:路径总和

思路:此题思路为递归实现,递归思路为:在每层递归的过程中将各个节点的数据记录下来,不断将减少目标数据的值准备进行判断,当进行到叶子节点时要进行判断 /*** Definition for a binary tree node.* struct TreeNode {…

服务式办公室联合办公空间,傻傻分不清楚

服务式办公室是一种灵活的办公解决方案,适合各种规模和类型的企业,尤其是那些寻求成本效益和灵活租赁条件的新兴企业。以下是服务式办公室的主要使用者和设施特点: 谁会使用服务式办公室? 新兴初创企业:由于初创企业在…

面试笔记系列四之SpringBoot+SpringCloud+计算机网络基础知识点整理及常见面试题

目录 Spring Boot 什么是 Spring Boot? Spring Boot 有哪些优点? SpringBootApplication注解 Spring Boot 的启动流程 Spring Boot属性加载顺序 springboot自动配置原理是什么?(*) 如何理解springboot中的start…

Leetcode—64. 最小路径和【中等】

2024每日刷题&#xff08;116&#xff09; Leetcode—64. 最小路径和 实现代码 class Solution { public:int minPathSum(vector<vector<int>>& grid) {int m grid.size();int n grid[0].size();vector<vector<int>> dp(m 1, vector<int&g…

配电房智能辅助监控系统设计

业务背景 工业企业、学校、医院、居民小区等单位有这海量的配电房&#xff0c;这些配电房内的配电设备种类多、运行环境复杂&#xff0c;存在各种各样的安全隐患。目前这些配电房主要依靠人员在场值守或巡检方式进行管理&#xff0c;但单纯的人工运维方式既成本高&#xff0c;…

pycharm基本操作,零基础快速上手

新建项目 pycharm安装完成后&#xff0c;双击pycharm的图标&#xff0c;打开pycharm。如果是首次使用的话选择Create New Project创建一个新项目。 进入pycharm后也可以通过以下方式新建一个项目&#xff0c;点击菜单栏File–New Project。 2. 选择项目路径和python环境&…

C++设计模式——抽象工厂模式

文章目录 抽象工厂模式的主要组成部分抽象工厂模式的一个典型例子抽象工厂模式用于其他场景抽象工厂模式与其他设计模式结合使用 C 中的抽象工厂模式是一种创建型设计模式&#xff0c;它主要用于处理对象家族的创建&#xff0c;这些对象之间可能存在一定的关联关系或属于相同的…

开仓济民 SWUST OJ 1175

有个王国在某年爆发了旱灾&#xff0c;于是那里的国王准备开仓济民。已知&#xff0c;第一天发一公斤粮食&#xff0c;第二天发两公斤粮食&#xff0c; 第三天发四公斤粮食。。。。。第二天发的粮食是前一天的两倍。我们已知安抚灾民一共需要m公斤粮食&#xff0c;问第几天国 王…

接口被恶意刷了!老板怒吼一声而我打开这篇文章!

在网络安全领域&#xff0c;恶意刷接口是一种常见的攻击手段&#xff0c;可能导致服务资源耗尽、数据泄露等严重后果。为了应对这一问题&#xff0c;我们需要采取一系列防范措施。 防火墙 数据包过滤与验证&#xff1a;防火墙具备对传入和传出网络的数据包进行深度分析和过滤…

【python】Python Turtle绘制流星雨动画效果【附源码】

在这篇技术博客中&#xff0c;我们将学习如何使用 Python 的 Turtle 模块绘制一个流星雨的动画效果。通过简单的代码实现&#xff0c;我们可以在画布上展现出流星闪耀的场景&#xff0c;为视觉带来一丝神秘与美感。 一、效果图&#xff1a; 二、准备工作 &#xff08;1)、导入…