传输层协议 TCP

TCP 协议


TCP 全称为 "传输控制协议(Transmission Control Protocol"). 人如其名, 要对数据的传输进行一个详细的控制

TCP 协议段格式

  • 源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去
  • 32 位序号/32 位确认号
  • 4 位 TCP 报头长度: 表示该 TCP 头部有多少个 32 位 bit(有多少个 4 字节), 所以TCP 头部最大长度是 15 * 4 = 60
  • 6位标志位
  • 16 位窗口大小
  • 16 位校验和: 发送端填充, CRC 校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含 TCP 首部, 也包含 TCP 数据部分.
  • 16 位紧急指针: 标识哪部分数据是紧急数据;
  • 40 字节头部选项

内核中对报头的描述

六个标志位

表示对应的报文类型,对应的六个比特位,要用就设置成1

  1. URG: 紧急指针是否有效
  2. ACK: 确认号是否有效
  3. PSH: 提示接收端应用程序立刻从 TCP 缓冲区把数据读走
  4. RST: 通信异常对方要求重新建立连接; 我们把携带 RST 标识的称为复位报文段
  5. SYN: 请求建立连接; 我们把携带 SYN 标识的称为同步报文段
  6. FIN: 通知对方, 本端要关闭了, 我们称携带 FIN 标识的为结束报文段

ACK一般都是置1,因为确认需要是要用来表示自己在该确认序号之前的报文全部收到,通常确认序号要有效,第一次建立连接SYN然后等待对方发送SYN和ACK,然后对方再用ACK告诉自己收到了建立请求,双方都有意愿建立连接,FIN用于断开连接时告诉对方断开连接,双方都要断开,所以得先发ACK给对方,对方响应了然后发送ACK和FIN

三次握手能保证一定连接成功C端发送SYN对方能收到,对方会给予回应,自己也能收到,自己在告诉对方收到了,在这个过程中,C和S发了一次收了一次,能最小代价验证自己和对方全双工并且建立连接成功,如果中间一环出错就代表建立不成功无法通信

 

16位窗口大小

网络传输需要消耗资源,为了提高效率,对方接受不了那么多,就控制一下发送的量,16位窗口大小表示自己接受缓冲区的剩余空间的大小用来告诉对端自己的剩余大小

16位紧急指针 

配合URG来用,数据发送到接收缓冲区后,它是一个字节流式的接受队列,提高优先级,优先处理,紧急指针表示偏移量位置存放紧急数据

 

确认应答(ACK)机制

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

每一个 ACK 都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发.向对方发送数据的时候不知道对方有没有收到,对端会送一个带有确认需要的报文并将ACK标记为置1,表示该确认序号以前的报文全部收到

为什么又两个序号?

一个确认序号,一个序号,因为TCP是全双工,可以发也可以读,在接受的同时也可以发,我告诉对方收到了,我也可以发送别的数据,就像三次握手一样,本质是四次握手,但是有两次合并了,当成一条报文发送,这就是要有一对序号的原因,一个负责发带编号,一个用来确定自己有没有收到,可以捎带应答,我告诉你我收到了,我也可以携带数据给你

 捎带应答


在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 "一发一收"的. 意味着客户端给服务器说了 "How are you", 服务器也会给客户端回一个 "Fine,thank you",那么这个时候 ACK 就可以搭顺风车, 和服务器回应的 "Fine, thank you" 一起回给客户端

超时重传机制

主机 A 发送数据给 B 之后, 可能因为网络拥堵等原因, 数据无法到达主机 B;如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会进行重发,但是, 主机 A 未收到 B 发来的确认应答,也可能是因为 ACK 丢失了

因此主机 B 会收到很多重复数据. 那么 TCP 协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉.这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果.那么, 如果超时的时间如何确定?

最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回",但是这个时间的长短, 随着网络环境的不同, 是有差异的.如果超时时间设的太长, 会影响整体的重传效率,如果超时时间设的太短, 有可能会频繁发送重复的包;

TCP 为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间.

Linux 中(BSD Unix 和 Windows 也是如此), 超时以 500ms 为一个单位进行控制, 每次判定超时重发的超时时间都是 500ms 的整数倍.如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接.

第一种可以用超时重传机制解决,但是第二种,因为确认序号的定义是在这个序号之前的报文全部收到,后续接收更大的序号也默认认为收到了

连接管理机制


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

三次握手,本质是四次握手,一方发起连接SYN,然后对端收到后,发送ACK应答,然后再发送SYN向对方请求连接,但是捎带应答使两个报文合成一条发送过去,最后对端收到货,返回ACK,表示同意连接,至此双方意愿达成可进通信

四次挥手,一方发起FIN向对方表示要断开连接,对方发送ACK表示接收到了断开请求,然后自己在向先有断开意愿的一方发送FIN断开请求,对端收到后,返回ACK表示同意,至此双方都断开对方的连接,结束通信

服务端状态转化:

  • [CLOSED -> LISTEN] 服务器端调用 listen 后进入 LISTEN 状态, 等待客户端连接
  • [LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送 SYN 确认报文.
  • [SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入ESTABLISHED 状态, 可以进行读写数据了.
  • [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用 close), 服务器会收到结束报文段, 服务器返回确认报文段并进入 CLOSE_WAIT(谁先关闭谁就CLOSE_WAIT,依旧占用文件描述符没有被释放,要手动关,不然fd泄漏
  • [CLOSE_WAIT -> LAST_ACK] 进入 CLOSE_WAIT 后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用 close 关闭连接时, 会向客户端发送FIN, 此时服务器进入 LAST_ACK 状态, 等待最后一个 ACK 到来(这个 ACK 是客户端确认收到了 FIN)
  • [LAST_ACK -> CLOSED] 服务器收到了对 FIN 的 ACK, 彻底关闭连接.

客户端状态转化:

  • [CLOSED -> SYN_SENT] 客户端调用 connect, 发送同步报文段
  • [SYN_SENT -> ESTABLISHED] connect 调用成功, 则进入 ESTABLISHED 状态, 开始读写数据
  • [ESTABLISHED -> FIN_WAIT_1] 客户端主动调用 close 时, 向服务器发送结束报文段, 同时进入 FIN_WAIT_1
  • [FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入 FIN_WAIT_2, 开始等待服务器的结束报文段
  • [FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出 LAST_ACK
  • [TIME_WAIT -> CLOSED] 客户端要等待一个 2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入 CLOSED 状态.

下图是 TCP 状态转换的一个汇总:

较粗的虚线表示服务端的状态变化情况,较粗的实线表示客户端的状态变化情况,CLOSED 是一个假想的起始点, 不是真实状态

理解 TIME_WAIT 状态


现在做一个测试,首先启动 server,然后启动 client,然后用 Ctrl-C 使 server 终止,这时马上再运行 server, 结果是:

这是因为,虽然 server 的应用程序终止了,但 TCP 协议层的连接并没有完全断开,因此不能再次监 听同样的 server 端口. 我们用 netstat 命令查看一下:

TCP 协议规定,主动关闭连接的一方要处于 TIME_ WAIT 状态,等待两个MSL(maximum segment lifetime)的时间后才能回到 CLOSED 状态.我们使用 Ctrl-C 终止了 server, 所以 server 是主动关闭连接的一方, 在TIME_WAIT 期间仍然不能再次监听同样的 server 端口,MSL 在 RFC1122 中规定为两分钟,但是各操作系统的实现不同, 在 Centos7 上默认配置的值是60s,可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 查看 msl 的值;

想一想, 为什么是 TIME_WAIT 的时间是 2MSL?


MSL 是 TCP 报文的最大生存时间, 因此 TIME_WAIT 持续存在 2MSL 的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启, 可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的),同时也是在理论上保证最后一个报文可靠到达(假设最后一个 ACK 丢失, 那么服务器会再重发一个 FIN. 这时虽然客户端的进程不在了, 但是 TCP 连接还在, 仍然可以重发 LAST_ACK)

解决 TIME_WAIT 状态引起的 bind 失败的方法(作业)

在 server 的 TCP 连接没有完全断开之前不允许重新监听, 某些情况下可能是不合理的

服务器需要处理非常大量的客户端的连接(每个连接的生存时间可能很短, 但是每秒都有很大数量的客户端来请求).这个时候如果由服务器端主动关闭连接(比如某些客户端不活跃, 就需要被服务器端主动清理掉), 就会产生大量 TIME_WAIT 连接.由于我们的请求量很大, 就可能导致 TIME_WAIT 的连接数很多, 每个连接都会占用一个通信五元组(源 ip, 源端口, 目的 ip, 目的端口, 协议). 其中服务器的 ip 和端口和协议是固定的. 如果新来的客户端连接的 ip 和端口号和 TIME_WAIT 占用的链接重复了, 就会出现问题.

使用 setsockopt()设置 socket 描述符的 选项 SO_REUSEADDR 为 1, 表示允许创建端口号相同但 IP 地址不同的多个 socket 描述符

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

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

相关文章

RT-Thread的概念和移植

一、操作系统的概念 操作系统(英语:Operating System,缩写:OS)是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织用户交互的相互关联的系统软件程序。根据运行的环境,操作系统可以…

基于单片机倾角测量仪/角度测量/水平仪

传送门 👉👉👉👉其他作品题目速选一览表 👉👉👉👉其他作品题目功能速览 概述 本设计实现了一种基于单片机的高精度数字倾角测量仪。系统核心由倾角传感器(ADXL345倾…

深度学习 -- 初步认识Torch

深度学习 – 初步认识Torch 文章目录深度学习 -- 初步认识Torch一,认识人工智能1.1 人工智能的本质1.2 人工智能的实现过程二,认识Torch2.1简介2.2 概述2.3 Tensor的创建2.3.1 torch.tensor2.3.2 torch.Tensor三,创建线性和随机张量3.1创建线…

BGP的“聪明选路”遇上了TCP的“路径洁癖”,需人工调和

在路由器R1上有两条外网,WAN1和WAN2。R1上做了域名分流功能,全局网址分到WAN1,指定域名分到WAN2(优先级更高)。症状是用户反馈部分网页无法打开。于是各种检查尝试...... 2天过去了......最终结论是:即使S…

ACWing算法笔记 | 二分

🔍 C 二分查找双模板详解:左闭右开 vs 左闭右闭(二分笔记)二分查找(Binary Search)是一类高效的搜索算法,在 O(log n) 的时间复杂度下查找答案,适用于单调性问题。C STL 的 lower_bo…

centos 新加磁盘分区动态扩容

你不能直接将一个分区分配给/dev/mapper/centos-root,因为这是一个逻辑卷(属于 LVM 系统)。不过,你可以通过以下步骤将/dev/sda3添加到现有卷组或创建新的逻辑卷: 确认磁盘和分区信息 首先检查分区是否已格式化以及是否…

python学智能算法(二十六)|SVM-拉格朗日函数构造

【1】引言 前序学习进程中,已经了解了拉格朗日乘数法求极值的基本原理,也了解了寻找最佳超平面就是寻找最佳分隔距离。 这篇文章的学习目标是:使用拉格朗日乘数法获取最佳的分隔距离。 【2】构造拉格朗日函数 目标函数 首先是目标函数f&a…

智能制造——48页毕马威:汽车营销与研发数字化研究【附全文阅读】

涵盖了汽车行业数字化转型、汽车营销业务能力建设(以会员管理为例)以及汽车研发与创新能力建设等议题。毕马威认为,软件定义汽车已成为汽车行业中的核心议题,并围绕此议题提供了相关方案。在市场观点方面,毕马威与多家…

嵌入式学习-PyTorch(8)-day24

torch.optim 优化器torch.optim 是 PyTorch 中用于优化神经网络参数的模块,里面实现了一系列常用的优化算法,比如 SGD、Adam、RMSprop 等,主要负责根据梯度更新模型的参数。🏗️ 核心组成1. 常用优化器优化器作用典型参数torch.op…

PostgreSQL实战:高效SQL技巧

PostgreSQL PG 在不同领域可能有不同的含义,以下是几种常见的解释: PostgreSQL PostgreSQL(简称 PG)是一种开源的关系型数据库管理系统(RDBMS),支持 SQL 标准并提供了丰富的扩展功能。它广泛应用于企业级应用、Web 服务和数据分析等领域。 PostgreSQL 的详细介绍 Po…

3-大语言模型—理论基础:生成式预训练语言模型GPT(代码“活起来”)

目录 1、GPT的模型结构如图所示 2、介绍GPT自监督预训练、有监督下游任务微调及预训练语言模型 2.1、GPT 自监督预训练 2.1.1、 输入编码:词向量与位置向量的融合 2.1.1.1、 输入序列与词表映射 2.1.1.2、 词向量矩阵与查表操作 3. 位置向量矩阵 4. 词向量与…

【Redis 】看门狗:分布式锁的自动续期

在分布式系统的开发中,保证数据的一致性和避免并发冲突是至关重要的任务。Redis 作为一种广泛使用的内存数据库,提供了实现分布式锁的有效手段。然而,传统的 Redis 分布式锁在设置了过期时间后,如果任务执行时间超过了锁的有效期&…

MYSQL--快照读和当前读及并发 UPDATE 的锁阻塞

快照读和当前读在 MySQL 中,数据读取方式主要分为 快照读 和 当前读,二者的核心区别在于是否依赖 MVCC(多版本并发控制)的历史版本、是否加锁,以及读取的数据版本是否为最新。以下是详细说明:一、快照读&am…

css样式中的选择器和盒子模型

目录 一、行内样式二、内部样式三、外部样式四、结合选择器五、属性选择器六、包含选择器七、子选择器八、兄弟选择器九、选择器组合十、伪元素选择器十一、伪类选择器十二、盒子模型 相关文章 学习标签、属性、选择器和外部加样式积累CSS样式属性:padding、marg…

关于基于lvgl库做的注册登录功能的代码步骤:

以下是完整的文件拆分和代码存放说明,按功能模块化划分,方便工程管理:一、需要创建的文件清单 文件名 作用 类型 main.c 程序入口,初始化硬件和LVGL 源文件 ui.h 声明界面相关函数 头文件 ui.c 实现登录、注册、主页面的UI 源文…

RAII机制以及在ROS的NodeHandler中的实现

好的,这是一个非常核心且优秀的设计问题。我们来分两步详细解析:先彻底搞懂什么是 RAII,然后再看 ros::NodeHandle 是如何巧妙地运用这一机制的。1. 什么是 RAII 机制? RAII 是 “Resource Acquisition Is Initialization” 的缩写…

Linux LVS集群技术

LVS集群概述1、集群概念1.1、介绍集群是指多台服务器集中在一起,实现同一业务,可以视为一台计算机。多台服务器组成的一组计算机,作为一个整体存在,向用户提供一组网络资源,这些单个的服务器就是集群的节点。特点&…

spring-ai-alibaba如何上传文件并解析

问题引出 在我们日常使用大模型时,有一类典型的应用场景,就是将文件发送给大模型,然后由大模型进行解析,提炼总结等,这一类功能在官方app中较为常见,但是在很多模型的api中都不支持,那如何使用…

「双容器嵌套布局法」:打造清晰层级的网页架构设计

一、命名与核心概念 “双容器嵌套布局法”,核心是通过两层容器嵌套构建网页结构:外层容器负责控制布局的“宏观约束”(如页面最大宽度、背景色等),内层容器聚焦“微观排版”(内容居中、内边距调整、红色内容…

基于深度学习的自然语言处理:构建情感分析模型

前言 自然语言处理(NLP)是人工智能领域中一个非常活跃的研究方向,它致力于使计算机能够理解和生成人类语言。情感分析(Sentiment Analysis)是NLP中的一个重要应用,其目标是从文本中识别和提取情感倾向&…