详解TCP协议

news2025/1/11 10:33:07

TCP协议段格式

在这里插入图片描述

  • 序号和确认序号:在真实服务器和客服端通信过程中请求是并行执行的,这会导致到达是乱序的,所以才会有序号这个东西,确认序号是对方应答时返回的,例如序号发送到1,确认序号会返回2,表示2之前的都收到了(是连续的都收到了!)那为什么得专门分成序号和确认序号呢?因为是全双工的,client的序号和server的确认序号是一组,client的确认序号和server的序号是一组
  • 16位校验和: 发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题。此处的检验和不光包含TCP首部, 也包含TCP数据部分
  • 16位接收窗口:在真实通信中因为是并行的,对方的接收缓冲区可能被打满,我们需要得知对方的剩余接收缓冲区,这样就可以在全双工通信中实现流量控制
  • 6位标志位:

URG(带外数据): 紧急指针是否有效,配合紧急数据指针来使用,起始位置(有效载荷)+16位紧急数据指针(偏移量),后面的1个字节为紧急任务,recv设置flag为MSG_OOB,send也把flag设置为MSG_OOB这样就可以发送和接收带外数据
ACK: 确认号是否有效
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走
RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段,通信过程中,连接单方面出现问题,例如服务器挂了,但是client还认为连接存在,我们在请求时server把RST位设置为1,告诉对方需要重新建立连接
SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段
FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段

1.如何封装解包

TCP有标准长度,先读取前20字节,因为是一个结构化的数据,所以可以提取4bit首都长度,这个4bit表示tcp报头总长度,所以取值范围是[0000,1111]→[0,15]但是这不对啊,tcp报头最少20字节,所以默认要*4,[0,60],因为最少是20,所以是[20,60],这样就可以得到后续选项的长度,报头处理完毕以后,最后剩下的就是有效载荷了。

2.如何分用?

根据目的端口号,就可以找到应用层进程

细心的读者会发现,UDP的长度是包括有效载荷的长度,而TCP并没有,这也是为什么TCP是面向字节流的原因

3.收到一个报文,是如何找到曾经bind特定port的进程的?

利用哈希可以快速定位

确认应答(ACK)机制

在这里插入图片描述

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

超时重传机制

情况一:

在这里插入图片描述

情况二:

在这里插入图片描述

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

重点:发送端,发出的数据必须要被维持一段时间,收到应答之后才可以删除!

超时时间规则如下:

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

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

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

连接管理机制

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

三次握手:

在这里插入图片描述

学了上面的东西,我们在重新理解一下这个过程,这里的SYN和ACK的设置就是更改报头的ACK和SYN标志位

四次挥手:

在这里插入图片描述

主动断开连接的一方,最终状态时TIME_WAIT,四次挥手动作已经完成,但是主动断开连接的一方要维持一段时间(2*MSL)的TIME_WAIT,为什么要维持这个状态?1.保证最后一个ACK尽可能被收到 2.双方在断开连接时,网络中还有滞留的报文——保证滞留报文消散

被动断开连接的一方,两次挥手完成是CLOSE_WAIT状态,可以通过不close服务端显示出这种情况

1.学了以上知识我们就可以解释为什么服务器会bind失败?

答:服务器是主动断开连接的一方,它会处于TIME_WAIT状态,而处于这个状态时,该端口和连接依旧被占用,所以无法bind

2.解决bind失败的方法

在这里插入图片描述

流量控制

前文我们知道TCP协议段格式中有一条叫做窗口大小,这个就是负责流量控制的,以免发送速度过慢或者过快。

1.我们如何第一次就知道对方缓冲区的大小的呢?

在通信之前,我们就做过了三次握手,交换窗口大小
接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过ACK端通知发送端;
窗口大小字段越大, 说明网络的吞吐量越高;
接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;
发送端接受到这个窗口之后, 就会减慢自己的发送速度;
如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端

2.接收端如何把窗口大小告诉发送端呢?

回忆我们的TCP首部中, 有一个16位窗口字段, 就是存放了窗口大小信息;那么问题来了, 16位数字最大表示65535, 那么TCP窗口最大就是65535字节么?实际上, TCP首部40字节选项中还包含了一个窗口扩大因子M, 实际窗口大小是 窗口字段的值左移 M 位;

滑动窗口

在这里插入图片描述

滑动窗口的大小是变化的!滑动窗口大小=min(对方的接收缓冲区,拥塞窗口),可能变大也可能变小

1.数据没丢,只是应答丢失了

在这里插入图片描述

2.数据真的丢了

如上图,那么就是应答错误的那个序号,滑动窗口不会向后滑动,连续收到3个包括3个就会触发重传机制

以上我们讨论的都是端到端的情况,也就是说我们讨论的都是双方的问题,没有考虑到网络的问题,所以就会有拥塞控制

拥塞控制

虽然TCP有了滑动窗口这个大杀器, 能够高效可靠的发送大量的数据。 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题。因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵。在不清楚当前网络状态下, 贸然发送大量的数据,是很有可能引起雪上加霜的

TCP引入慢启动机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据。

此处引入一个概念程为拥塞窗口。发送开始的时候, 定义拥塞窗口大小为1。每次收到一个ACK应答, 拥塞窗口*2。每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口。

像上面这样的拥塞窗口增长速度, 是指数级别的。 “慢启动” 只是指初使时慢, 但是增长速度非常快。
为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍,此处引入一个叫做慢启动的阈值,当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长

在这里插入图片描述

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

少量的丢包, 我们仅仅是触发超时重传; 大量的丢包, 我们就认为网络拥塞;
当TCP通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降;
拥塞控制, 归根结底是TCP协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案

延迟应答

如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小.

假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;
但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M

一定要记得, 窗口越大, 网络吞吐量就越大, 传输效率就越高. 我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;

那么所有的包都可以延迟应答么? 肯定也不是;

数量限制: 每隔N个包就应答一次;
时间限制: 超过最大延迟时间就应答一次

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

捎带应答

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

面向字节流

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

  • 调用write时, 数据会先写入发送缓冲区中;
  • 如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;
  • 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出去;
  • 接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;
  • 然后应用程序可以调用read从接收缓冲区拿数据;
  • 另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据, 也可以写数据. 这个概念叫做 全双工

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

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

TCP异常情况

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

TCP总结

可靠性:

校验和
序列号(按序到达)
确认应答
超时重发
连接管理
流量控制
拥塞控制

提高性能:

滑动窗口
快速重传
延迟应答
捎带应答

其他:

定时器(超时重传定时器, 保活定时器, TIME_WAIT定时器等)

基于TCP应用层协议

HTTP
HTTPS
SSH
Telnet
FTP
SMTP

学完以上知识,请问如果想用UDP实现可靠传输该怎么做呢?

1.引入序列号,保证数据顺序 2.引入确认应答 3.引入超时重传 等

listen第二个参数

listen(int socket, int backlog);

第二个参数backlog代表等待队列的最大长度

在这里插入图片描述

客户端:

当connect到来的时候无论等待队列有没有空余地方在客户端眼里都是连接成功的,因为一开始调用connect函数SYN请求,服务端立刻给予客户端SYN+ACK确认,客户端连接状态从SYN_SENT转换到ESTABLISHED之后再向服务端发ACK确认。也就是所谓的三次握手过程

服务端:

当客户端connect来到时,服务端进入SYN_RCVD状态并给予SYN+ACK响应。当下次客户端完成三次握手,收到客户端的ACK时:如果队列中有空间,则服务端的连接也建立成功,否则服务端眼里没有成功。每建立成功一次,要往队列中放入刚才建立好的连接,也就是队列空间-1,服务端状态从SYN_RCVD变为ESTABLISHED,如果不成功还是原来的SYN_RCVD状态。当服务端调用accept成功时,又是队列空间+1,从队列中拿走一个连接。

Linux内核协议栈为一个tcp连接管理使用两个队列:

  1. 半链接队列(用来保存处于SYN_SENT和SYN_RECV状态的请求)
  2. 全连接队列(accpetd队列)(用来保存处于established状态,但是应用层没有调用accept取走的请求)

而全连接队列的长度会受到 listen 第二个参数的影响。全连接队列满了的时候, 就无法继续让当前连接的状态进入 established 状态了。这个队列的长度是 listen 的第二个参数 + 1。

测试:

把listen的第二个参数设置为1,并且把accept函数屏蔽掉,不让执行下去。这样保证迟早队列中会没有地方,导致有的连接不成功。

在这里插入图片描述

一共开了4个客户端,但从上图中可以看到只有两个服务端是成功的,另外两个还在上一个状态中,但是所有的客户端都是成功的。所以说明最大队列个数是backlog+1

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

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

相关文章

计算机网络 day6 arp病毒 - ICMP协议 - ping命令 - Linux手工配置IP地址

目录 arp协议 arp病毒\欺骗 arp病毒的运行原理 arp病毒产生的后果: 解决方法: ICMP协议 ICMP用在哪里? ICMP协议数据的封装过程 ​编辑 为什么icmp协议封装好数据后,还要加一个ip包头,再使用ip协议再次进…

springboot农机电招平台

本系统为了数据库结构的灵活性所以打算采用MySQL来设计数据库,而java技术,B/S架构则保证了较高的平台适应性。本文主要介绍了本系统的开发背景,所要完成的功能和开发的过程,主要说明了系统设计的重点、设计思想。 本系统主要是设…

关于java垃圾回收的小结

一、为什么要有垃圾回收 我们每次创建对象都需要在栈上开辟空间,堆上使用内存,如果我们只是开辟了这个空间,而不去释放他,那么再大的内存和空间也会有满的一天,所以我们在Java中引入了GC(垃圾回收机制&…

Foxit PDF ActiveX 5.9.8 Crack

Foxit PDF SDK ActiveX 即时添加PDF显示功能至Windows应用程序,快速投放市场,可视化编程组件功能强大且易于使用的PDF软件开发工具包 对于刚接触PDF或不愿投入过多精力学习PDF技术的产品管理者及开发者来说,Foxit PDF SDK ActiveX无疑是理想…

中国1km分辨率逐月平均气温数据集(1901-2022)

时间分辨率月空间分辨率1km - 10km共享方式开放获取数据大小9.71 GB数据时间范围 1901.1-2022.12 数据集摘要 该数据为中国逐月平均温度数据,空间分辨率为0.0083333(约1km),时间为1901.1-2022.12。数据格式为NETCDF,即.nc格式。数据单位为0.1 ℃。该数据集是根据CRU发布的…

对Vue组件化开发思想的一些理解

目录 组件的分类 为什么需要组件化开发 如何设计组件 组件间通信 组件系统是 Vue的一个重要概念,让我们可以用独立可复用的小组件来构建大型应用。几乎任意类型的应用的界面都可以抽象为一个组件树: 写一个 Vue 项目,其实就是在写一个个的…

接口测试 react+unittest+flask 接口自动化测试平台

目录 1 前言 2 框架 2-1 框架简介 2-2 框架介绍 2-3 框架结构 3 平台 3-1 平台组件图 1 新建用例 2 生成测试任务 3 执行并查看测试报告 3-2 用例管理 3-2-1 用例设计 3-3 任务管理 3-3-1 创建任务 3-3-2 执行任务 3-3-3 测试报告 3-3-4 邮件通知 1 前言 构建…

idea新建xml模板设置,例如:mybatis-config

在idea怎么新建mapper.xml文件&#xff0c;具体操作步骤和结果如下&#xff0c;其他文件也是可以自定义模板的流程和步骤一致&#xff01; 效果如下&#xff1a; 步骤如图&#xff1a; step1&#xff1a; step2&#xff1a; 文件内容&#xff1a; <?xml version"…

Android.mk 文件使用解析

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、Android.mk 简介二、Android.mk 的基本格式三、Android.mk 深入学习一四、 Android.mk 深入学习二五、 Android.mk 深入学习三六、 Android.mk 判断…

C++【哈希表的模拟实现】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; C修行之路 &#x1f383;操作环境&#xff1a; Visual Studio 2019 版本 16.11.17 文章目录 &#x1f307;前言&#x1f3d9;️正文1、模拟实现哈希表&#xff08;闭散列&#xff09;1.1、存储数据结构的定义1…

MySQL函数以及存储过程

创建表并插入数据‘ 字段名 数据类型 主键 外键 非空 唯一 自增 id INT 是 否 是 是 否 name VARCHAR(50) 否 否 是 否 否 glass VARCHAR(50) 否 否 是 否 否 sch 表内容 id name glass 1 xiaommg glass 1 2 xiaojun glass 2 mysql> select * from sch; -------------------…

火车头采集器下载中文图片地址报错:发生错误终止..

火车头采集器下载中文图片地址报错&#xff1a;发生错误终止.. 报错信息 该问题时网友发现的&#xff0c;采集的内容中图片URL地址包含中文字符。 然后在采集内容时火车头自动下载图片就提示&#xff1a;发生错误终止&#xff0c;远程服务器返回错误&#xff1a;&#xff08…

MySQL 主从延迟的常见原因及解决方法

主从延迟作为 MySQL 的痛点已经存在很多年了&#xff0c;以至于大家都有一种错觉&#xff1a;有 MySQL 复制的地方就有主从延迟。 对于主从延迟的原因&#xff0c;很多人将之归结为从库的单线程重放。 但实际上&#xff0c;这个说法比较片面&#xff0c;因为很多场景&#xf…

我司的短信接口被刷了

如何发现的 成本分摊系统&#xff0c;将成本分摊给业务部门时&#xff0c;业务部门对账&#xff0c;发现某一类型的短信用量上涨了100多倍 排查调用来源时&#xff0c;发现来源为C端用户&#xff0c;由于调用量异常高&#xff0c;业务反馈近期无活动&#xff0c;因此怀疑被刷…

GAMES101 作业0

Visual Studio 2019下环境配置 课上提供的环境是Linux, 还需要安装Vitrual Box和创建虚拟机&#xff0c;省事就直接在Windows系统下Visual Studio下操作了。 简单的环境配置&#xff1a; 下载Eigen 的库在工程属性中添加目录&#xff1a; 2处地方 注意&#xff1a; 刚添加完…

CONTAINER = ALL是ALTER USER语句的默认值

连接到root时查看有关root&#xff0c;CDB和PDB的数据 当公用用户执行查询时&#xff0c;可以限制X $表和V $&#xff0c;GV $和CDB_ *视图的视图信息。X$表和这些视图包含有关应用程序root及其关联应用程序PDB的信息&#xff0c;或者如果连接到CDB root&#xff0c;则是整个C…

基于非支配排序遗传算法NSGAII的综合能源优化调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

松鼠回家(最短路+二分)

D-松鼠回家_2023河南萌新联赛第&#xff08;一&#xff09;场&#xff1a;河南农业大学 (nowcoder.com) #include<bits/stdc.h> using namespace std; #define int long long const int N2e510; map<int,int>a; int n,m,st,ed,h; struct node{int x,y; }; vector&l…

解密Prompt系列4. 升级Instruction Tuning:Flan/T0/InstructGPT/TKInstruct

这一章我们聊聊指令微调&#xff0c;指令微调和前3章介绍的prompt有什么关系呢&#xff1f;哈哈只要你细品&#xff0c;你就会发现大家对prompt和instruction的定义存在些出入&#xff0c;部分认为instruction是prompt的子集&#xff0c;部分认为instruction是句子类型的prompt…

wangEditor富文本编辑器的调用开发实录2(V5版本自定义粘贴,去除复制word或网页html冗余样式代码的解决方案)

wangEditor富文本编辑器&#xff1a;自定义粘贴&#xff0c;去除复制word或网页html冗余样式代码的解决方案 1.环境说明2.解决方案3.完整代码总结 在使用wangEditor富文本编辑器时&#xff0c;当从word文档或者其他网页复制文本内容粘贴到编辑器中&#xff0c;如果不过滤掉复制…