TCP协议重点总结(万字总结-附实例)

news2024/11/17 20:21:43

文章目录

  • 前言
  • 一、网络的原生情况
  • 二、TCP协议
    • 2.1 TCP的特点
    • 2.2 TCP协议段格式
    • 2.3 TCP原理
      • 2.3.1 确认应答机制(可靠机制)
      • 2.3.2 序列号
      • 2.3.3 超时重传机制(可靠机制)
      • 2.3.4 连接管理机制(可靠机制)
      • 2.3.5 滑动窗口机制(效率机制)
    • 2.4 关于缓冲区
    • 2.5 关于ISN
    • 2.6 关于面向字节流
  • 三、实例演示(抓包)
  • 四、 TCP中的状态转移(重要)
  • 五、TCP异常情况
  • 六、关于粘包
  • 七、命令行查看TCP连接情况
  • 总结


前言

博主个人社区:开发与算法学习社区

博主个人主页:Killing Vibe的博客

欢迎大家加入,一起交流学习~~

一、网络的原生情况

网络中的数据,是经过路由器之间,一跳一跳地,接力一样地,传送到目标主机上的。

这带来了两个问题:(站在网络层的视角上讨论)

✦ 网络传送是不可靠的

  1. 你的发送了数据,对方不保证一定能收到
  2. 不能保证严格按照发送时的顺序被对方接收到

由于路可能不同,所以很难保证按照出发的顺序到达

在这里插入图片描述

✦ 网络传送是不安全的

  1. 你发送的所有数据,沿途的路由器都可以进行查看或者修改,窃听,篡改
  2. 别人可以伪造成你发送的数据

这两个问题需要交给网络层以上(传输层、应用层)去解决

这篇文章博主将详细总结一下传输层的TCP协议

二、TCP协议

TCP,即Transmission Control Protocol,传输控制协议。人如其名,要对数据的传输进行一个详细的控制。
在这里插入图片描述

2.1 TCP的特点

可靠的,有连接的,面向字节流的

什么是可靠性?

  1. TCP会尽自己所能,尽量将数据发送给对方;但并不能保证100%可以发给对方
  2. TCP会在数据发送不给对方的情况下,给应用层一个错误通知(应用层发送数据,要么发送给对方了,要么知道数据丢失了,UDP则不会
  3. TCP可以保障接收方(应用层)严格按照发送时的数据顺序接收。
  4. TCP保障数据不会出现无意间损坏(UDP也做到了这一点)
  5. TCP尽可能的在维护网络质量

2.2 TCP协议段格式

在这里插入图片描述

  • 源/目的端口号:表示数据是从哪个进程来,到哪个进程去;
  • 32位序号/32位确认号:下文详细讲;
  • 4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是15 * 4 = 60 字节
  • 6位标志位:
    ✭ URG:紧急指针是否有效
    ✭ ACK:确认号是否有效
    ✭ PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
    ✭ RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段
    ✭ SYN:请求建立连接;我们把携带SYN标识的称为同步报文段
    ✭ FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段
  • 16位窗口大小:下文详细讲
  • 16位校验和:发送端填充,CRC校验。接收端校验不通过,则认为数据有问题。此处的检验和不光包含TCP首部,也包含TCP数据部分。
  • 16位紧急指针:标识哪部分数据是紧急数据;
  • 40字节头部选项:暂时忽略

2.3 TCP原理

TCP对数据传输提供的管控机制,主要体现在两个方面:可靠和效率。

2.3.1 确认应答机制(可靠机制)

在这里插入图片描述

有了确认应答机制之后,现在还遗留两个问题:

  1. 如果发送方同时发送了很多数据,怎么知道对方确认收到的是哪一份?
  2. 如果没有收到对方的确认(假定对方是处于正常工作流程的),接下来该怎么办?

答:

  1. 对数据进行编号,这样,确认也带上编号,表明确认的是哪份数据。
  2. 进行重发,重发的触发有个条件 ——— 超过一定时间没有收到确认,才要重复。(这就是超时重传机制)

接下来就是围绕上述两个问题展开。

2.3.2 序列号

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

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

下面围绕数据的编号以及确认的编号来讨论:

  1. 发送的数据编号 —— 序列号(Sequence Number) SN
  2. 确认的数据编号 —— 确认序列号(Acknowledge Sequence Number)ASN

编号的规则

在这里插入图片描述

ASN的填写规则:

填写的是要接受的下一个字节的数据(本次收到的数据的最后一个字节的下一个)
在这里插入图片描述

SN在发送TCP Segment 时,Header中是如何体现的?

注意:

1.TCP发送/接收的完整数据,一般称为segment(段)
2.TCP segment = header + payload

举个栗子:

因为一次可以发送多个字节的数据

byte[] data = {1,2,3,4,5}
tcp.write(data);  //一次性发送了5个字节的数据

所以,SN直接填写本次发送的数据中第一个字节的数据即可。segment会携带payload长度 SN=a

TCP由于要进行发送,也要进行确认。所以实际上 TCP Segment有两种不同的角色:

  1. send segment
  2. acknowledge segment

TCP设计的时候,一个segment可以身兼两种不同的角色。

无论何时,一个segment 都视为send segment角色。

但当某个标志位被置位(开关被打开)时,segment具备了acknowledge segment的角色。

在这里插入图片描述

这个开关在TCP Header是通过ack标志位进行处理的:

在这里插入图片描述

2.3.3 超时重传机制(可靠机制)

在这里插入图片描述

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

但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了;

在这里插入图片描述
因此主机B会收到很多重复数据。那么TCP协议需要能够识别出那些包是重复的包,并且把重复的丢弃掉。

这时候我们可以利用前面提到的序列号,就可以很容易做到去重的效果。

那么,如果超时的时间如何确定?

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

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

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

TCP已经尽了自己最大的努力,接下来:

  1. 需要通知应用层,发送失败(一般在java中,write(…)就会以异常的形式提示)
  2. 尽自己最大的努力,再尝试联系一下对方(会发送一种叫做reset segment),对方如果收到了,就知道我这侧已经放弃了,如果对方收不到,也无所谓。

2.3.4 连接管理机制(可靠机制)

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

作为一台主机上的TCP,需要:

  1. 内部针对每一条TCP的通信链路(信道),维护一组数据
    至少:ISN、当前SN、当前ASN、发送缓冲区、接收缓冲区、五元组信息…
  2. TCP为了可靠性、为了交互交换一些信息,在正式的数据通信之前,需要和对方(TCP)进行一定的同步(synchronize)操作
  3. A把主机的一些初始重要信息告诉了B;然后B发送应答给A,让A知道B肯定也在

所以TCP就有了连接(Connection)的概念,以及连接管理(一条连接的医生= 开始创建+正式使用+销毁)

关于连接:

在这里插入图片描述

好了,有了如上的铺垫,接下来博主讲逐步讲解三次握手和四次挥手到底是怎么一回事:

✭ 握手阶段其实就是双方互相同步信息的阶段:

在这里插入图片描述

逻辑上需要四次,因为互相发同步信息(2次)都需要应答(2次)。

在这里插入图片描述

由于第二步和第三步是可以同时发生的,TCP也支持一个Segment同时起到(syn和ack)的作用,所以上述2和3可以合并,减少网络数据发送的次数,整体上提高性能。

在这里插入图片描述

✭ 同理,挥手阶段其实就是双方互相确认要断开连接的阶段:

  1. 不过由于服务器不能收到客户端的fin请求就立刻也发一个fin请求,因为服务器此时可能仍有一些未处理完的数据要处理,要等这些数据处理完才可以close。
  2. 还有种可能的情况就是双方都主动挥手close了。
  3. 还有种情况就是双方同时主动挥手。

情况一:

在这里插入图片描述

情况二:

在这里插入图片描述
情况三:
在这里插入图片描述

注意:

三次握手阶段是否可以携带payload?

  1. 第一次syn,不能携带数据
  2. 第二次syn+ack,不能携带数据
  3. 第三次ack,可以携带数据,但不强制

原因在于不能确认连接一定建立成功,如果携带数据,则提升发送成本,如果失败,一切白发,所以协议设计时禁止携带数据。

syn序列号的变化:虽然不能携带数据,但也会消耗一个序列号:

在这里插入图片描述

2.3.5 滑动窗口机制(效率机制)

这是一块重要的内容,博主直接分P详细总结并且画图逐步讲解了,链接如下:

TCP滑动窗口机制

2.4 关于缓冲区

在这里插入图片描述

2.5 关于ISN

在这里插入图片描述

2.6 关于面向字节流

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

三、实例演示(抓包)

用Wireshark抓包工具,抓取传输协议为TCP的包:

在这里插入图片描述以上就是三次握手的三个包。

下图为第一个包中的数据:(蓝色部分为TCP的部分)

在这里插入图片描述

在这里插入图片描述

现在可以根据这些数据来一一计算验证我们的TCP头:

在这里插入图片描述
验证如下:

16位源端口号:首先前面两个字节是 0xe542,换算成十进制就是 58690
16位目的端口号:然后就是后面的两个字节 0x22b8,换算过来就是 8888
32位SN: 0xb1e9b0e0 ,可以看出来ISN不是0。
32位ASN: 0x00000000,一开始发送的时候还没有ASN
4位首部长度: 0x8,说明协议首部长度为 8 * 4 = 32 字节(真实首部长度= 首部长度 * 4 ,像这里的8表示有8个32为bit,也就是8个4字节 = 32字节)
保留6位+标志位6位: 0x002 ,换算成二进制就是000000 000010,刚好对应的就是syn位被置为了1 .

后面的是一样计算的,博主就不一一列举了。

四、 TCP中的状态转移(重要)

以下内容博主也进行了分P总结,这块内容比较难理解,最好就是死记硬背,具体可以参考博主的图解,更容易理解,链接如下:

TCP中的状态转移(三种情况)

五、TCP异常情况

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

拓展:

进程终止和机器关机/重启:

一个进程的所有资源都是OS分配的(换言之,一个进程有哪些资源OS都是知道的),所以,即使进程内部没有关闭TCP连接,OS也会走进程资源释放流程,将TCP连接正常关闭,这个进程会作为主动关闭方,正常四次挥手

在这里插入图片描述

只要OS的代码能执行,连接就会正常关闭!!!

机器掉电/网线断开:

这种情况,OS的代码就不能执行了,因为机器掉电了。

此时这条连接的命运需要分开来讨论:

现在假设有两台主机 甲和乙。

  1. 首先是甲的命运:由于连接只是逻辑上的概念,表现在现实中只是内存中的一段数据。电断了,内存中的数据就没有了,所以对于甲来说连接就没了(不是关闭,直接就是消失了)
  2. 其实是乙的命运:在乙看来,连接仍然在,在没有特殊场景下,乙是不知道甲没了。(比如男女朋友的关系,男方突然挂了,女方不通过某些途径是不知道男方挂了的)
  3. 所以乙的情况就会有两种: (1)保持原状 (2) 看乙有没有可能感知到甲已经没了这条信息
  4. 如果乙发生写事件(乙尝试向甲发数据了),收不到ACK确认信息,即使超时重传了也收不到。多次尝试后,乙走异常关闭流程。(关闭该TCP连接,异常方式通知应用层,最后再发一条reset segment)
  5. 如果乙只是单纯在读数据,那么乙不知道甲已经消失了这个信息,如果乙一直read,则乙就是死连接了(一直保持established状态,但永远收不到数据了)

为了解决上述这个问题:

  1. TCP层面有keepalive机制:定期的发送一些数据给对方(payload长度为0),segment长度不是0,就可以根据对方有没有应答来判断。(用的不多)
  2. 更常见的办法是应用层自己来做这个工作:(1)read的时候,不要无限制read,而是带上超时时间(read timeout)。 (2) 定期互相报平安(定期都主动给对方发消息) ——heartbeat(心跳包)

例如QQ,在QQ断线之后,也会定期尝试重新连接。

关于RST:

在这里插入图片描述

六、关于粘包

  • 首先要明确,粘包问题中的 “包” ,是指的应用层的数据包。
  • 在TCP的协议头中,没有如同UDP一样的 “报文长度” 这样的字段,但是有一个序号这样的字段。
  • 站在传输层的角度,TCP是一个一个报文过来的。按照序号排好序放在缓冲区中。
  • 站在应用层的角度,看到的只是一串连续的字节数据。
  • 那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包。

那么如何避免粘包问题呢?归根结底就是一句话,明确两个包之间的边界

  • 对于定长的包,保证每次都按固定大小读取即可;例如上面的Request结构,是固定大小的,那么就从缓冲区从头开始按sizeof(Request)依次读取即可;
  • 对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置;
  • 对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是程序猿自己来定的,只要保证分隔符不和正文冲突即可);

七、命令行查看TCP连接情况

使用 netstat 命令:

在这里插入图片描述

由于输出较多,可以结合findstr 做结果过滤:

在这里插入图片描述
根据任务管理器,知道 pid为29632的进程占用了端口为8080的TCP连接:

在这里插入图片描述

总结

以上就是TCP协议的万字总结,内容有点多,但每个知识点的细节博主都有举实例,帮助大家更好的理解,码字不易,有帮助的话大家可以点个赞收藏起来慢慢看,有什么问题可以私信博主,大家交流一下。

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

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

相关文章

RabbitMQ的简介和简单使用

同步调用异步调用MQRabbitMQ的使用docker拉取docker pull rabbitmq:3-management启动容器docker run \-e RABBITMQ_DEFAULT_USERitcast \ (账号)-e RABBITMQ_DEFAULT_PASS123321 \ (密码)--name mq \--hostname mq1 \-p 15672:156…

开发工具中SpringBoot使用外置Tomcat启动 (亲测有效)-第458篇

历史文章(文章累计450) 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 SpringBoot添加外部jar包及打包(亲测有…

评测5款国内外免费远控,谁是最好用第一名?

远程控制应用不少人都有了解使用过,尤其是会常用电脑进行工作的群体,比如程序员、设计师、运维、文员等岗位。在隔离居家远程办公时,通过家里的手机、平板或电脑跨系统、跨设备操控公司所用的办公电脑,就能及时处理工作内容&#…

前端使用lottie-web,使用AE到处的JSON动画贴心教程

Lottie简介 官方介绍:Lottie是一个库,可以解析使用AE制作的动画(需要用bodymovie导出为json格式),支持web、ios、android、flutter和react native。 在web端,lottie-web库可以解析导出的动画json文件,并将其…

02_FreeRTOS移植

目录 获取FreeRTOS源码 FreeRTOS源码内容 FreeRTOS内核 Demo文件夹 Source文件夹 portable文件夹 FreeRTOS移植 移植步骤 移植详解 实验源码: 获取FreeRTOS源码 FreeRTOS官网:https://www.freertos.org/ FreeRTOS源码内容 FreeRTOS内核 Demo文件夹 Demo文件夹里面就…

《Protein Actions Principles and Modeling》-《蛋白质作用原理和建模》中文分享(15)

《Protein Actions Principles and Modeling》-《蛋白质作用原理和建模》 本人能力有限,如果错误欢迎批评指正。 第四章:Protein Binding Leads to Biological Actions (蛋白质的结合会产生生物作用) 如果我们想要对一个结合过…

Java 泛型中的通配符详解

目录 1、如何定义和使用上界通配符? 2、如何定义和使用无界通配符? 3、如何定义和使用下界通配符? 4、如何使用通配符定义泛型类或接口之间的子类型关系? 5、通配符的捕获和辅助方法 6、通配符使用指南 在泛型代码中&#x…

C++ txt文本文件处理系统(c++学习小例子)

C++ txt文本文件处理系统(c++学习小例子) 一、界面示例二、 要求2.1 数据格式2.2 实现功能三、代码3.1 classfi.h3.2 classfi.cpp3.3 main.cpp四、 使用说明一、界面示例 二、 要求 2.1 数据格式 现有DEM数据,其格式为DEM_data.txt,可在文章末尾下载。文本存储格式如下: …

用javascript分类刷leetcode19.数组(图文视频讲解)

数组操作的时间复杂度 Access:O(1) Search:O(n) Insert: 平均O(n),最好的情况下O(1),也就是在数组尾部插入O(1),最坏的情况下O(n) Delete;平均O(n),最好的情况下O(1),…

力扣刷题记录——367. 有效的完全平方数、383. 赎金信、387. 字符串中的第一个唯一字符、389. 找不同

本专栏主要记录力扣的刷题记录,备战蓝桥杯,供复盘和优化算法使用,也希望给大家带来帮助,博主是算法小白,希望各位大佬不要见笑,今天要分享的是——《367. 有效的完全平方数、383. 赎金信、387. 字符串中的第…

LightDB单机安装

LightDB单机安装 LightDB官网:https://www.hs.net/lightdb 下载安装包:lightdb-x-13.8-22.3-7953-el7.x86_64.zip 前置准备 防火墙配置(选择一种操作) firewall防火墙 firewall-cmd --permanent --add-port5432/tcp firewall-cmd --permanent --add-p…

(深度学习快速入门)第三章第三节2:深度学习必备组件之损失函数和激活函数

文章目录一:损失函数(1)均方误差损失(MSE)(2)交叉熵损失(Cross Entropy)二:激活函数(1)tanh(2)ReLU&#xff0…

SpringBoot数据响应与内容协商

目录 数据响应与内容协商 1、响应JSON 1.1、jackson.jarResponseBody 1.2、SpringMVC到底支持哪些返回值 2、内容协商 1、引入xml依赖 2、postman分别测试返回json和xml 3、开启浏览器参数方式内容协商功能 数据响应与内容协商 1、响应JSON 1.1、jackson.jarResponseBo…

区块链北大肖老师学习笔记6

第七节 比特币的挖矿难度调整 H(block header) < target 目标(target)预值越小&#xff0c;挖矿的难度越大。调整挖矿的难度就是调整目标空间在整个输出空间中所占的比例。 比特币用的哈希算法是SHA-256&#xff0c;这个产生的哈希值是256位。所以整个输出空间是2的256次…

[JavaEE]synchronized 与 死锁

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录 1.synchronized 的特性 2. synchronized 使用示例:…

new做了什么

function structure (name, age) {this.name namethis.age age}// 给构造函数--prototype加上一个方法structure.prototype.sayName function () {console.log(this.name, 调用打印);return this.name}structure.one 5const person new structure(张龙, 188)// 打印构造函…

【基础算法】前缀和 与 差分

前缀和 用来求解一段区间&#xff08;一维&#xff09;的总和 或者一块矩形区域&#xff08;二维&#xff09;的总和 一维前缀和 原数组a[N]&#xff0c;前缀和数组s[N]// ---读入数组a[N] // ---// 处理前缀和数组 s[N] s[0] 0; //定义在全局变量&#xff0c;不用写这一句 f…

SOA 和微服务有何区别?

玩过 Dubbo 的小伙伴应该都有听说过一个概念叫做 SOA&#xff0c;每当我们说起微服务的时候&#xff0c;很多人就会去纠结这和 SOA 有啥关系呀&#xff1f;感觉换汤不换药呀。 今天松哥来稍微和小伙伴们讨论下这个话题&#xff0c;我们一起来看看 SOA 和微服务到底有何异同。 …

c语言进阶(3)——指针进阶笔试题详解

1.指针和数组笔试题解析 关键&#xff1a;数组名在两种情况下是指整个数组&#xff1a; &#xff08;1&#xff09;sizeof&#xff08;数组名&#xff09;&#xff08;2&#xff09;&数组名 其它的情况下&#xff0c;都是代表数组的首元素地址。 例题 1 &#xff1a;一维…

【算法面试】算法在面试中考察的是什么(金三银四面试专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/Liunx内核/C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1f4…