传输层协议 --TCP报文格式详细介绍

一、 TCP协议格式

TCP如何将报头与有效载荷进行分离?

  当TCP从底层获取到一个报文后,虽然TCP不知道报头的具体长度,但报文的前20个字节是TCP的基本报头,并且这20字节当中涵盖了4位的首部长度。

因此TCP是这样分离报头与有效载荷的:

1) 当TCP获取到一个报文后,首先读取报文的前20个字节,并从中提取出4位的首部长度,此时便获得了TCP报头的大小size。
2)如size的值大于20字节,则需要继续从报文当中读取s i z e − 20 size-20size−20字节的数据,这部分数据就是TCP报头当中的选项字段。
3)读取完TCP的基本报头和选项字段后,剩下的就是有效载荷了。

需要注意的是,TCP报头当中的4位首部长度描述的基本单位是4字节,这也恰好是报文的宽度。4为首部长度的取值范围是0000 ~ 1111,因此TCP报头最大长度为15 × 4 = 60 字节,因为基本报头的长度是20字节,所以报头中选项字段的长度最多是40字节。

如果TCP报头当中不携带选项字段,那么TCP报头的长度就是20字节,此时报头当中的4位首部长度的值就为20 ÷ 4 = 5,转为二进制也就是0101

1. 序号和确认序号

确认序号表示序号对应的数字,确认序号被设置表示之前所有的报文都一斤全部收到了,告诉对方下次从确认序号知名的序号开始发送。(往往给对方发送消息就是应答)

  client依次可能会向服务器发送多个报文,就有一个问题:发送顺序和接受顺序不同(数据包乱序问题),client如何确认那个应答对应那个发送嘞?

   序号和确认序号的作用就在此很好的发挥了,首先 序号和确认序号可以将请求和应答一 一对应,收到的报文如果是乱序的,可以对序号进行排序(解决乱序问题),其次 确认序号表示序号确认之前的序号全部收到,也就允许部分确认丢失是或者不给应答。

既然给对方发送信息本身就是一种应答,为什么要有两个字段?

  因为TCP是全双工的,任何一方技能发送也能接收,所以必须要有两个字段将他们区分开。

 2. TCP报头的6个标志位

 SYN 连接请求标志位

报文当中的SYN被设置为1,表明该报文是一个连接建立的请求报文。
只有在连接建立阶段,SYN才被设置,正常通信时SYN不会被设置。


ACK  报文当中的ACK被设置为1,表明该报文可以对收到的报文进行确认。

一般除了第一个请求报文没有设置ACK以外,其余报文基本都会设置ACK,因为发送出去的数据本身就对对方发送过来的数据具有一定的确认能力,因此双方在进行数据通信时,可以顺便对对方上一次发送的数据进行响应。


FIN 连接断开请求标志位

报文当中的FIN被设置为1,表明该报文是一个连接断开的请求报文。
只有在断开连接阶段,FIN才被设置,正常通信时FIN不会被设置。

URG 紧急标志位,配合16位紧急指针使用

双方在进行网络通信的时候,由于TCP是保证数据按序到达的,即便发送端将要发送的数据分成了若干个TCP报文进行发送,最终到达接收端时这些数据也都是有序的,因为TCP可以通过序号来对这些TCP报文进行顺序重排,最终就能保证数据到达对端接收缓冲区中时是有序的。

TCP按序到达本身也是我们的目的,此时对端上层在从接收缓冲区读取数据时也必须是按顺序读取的。但是有时候发送端可能发送了一些“紧急数据”,这些数据需要让对方上层提取进行读取,此时应该怎么办呢?

此时就需要用到URG标志位,以及TCP报头当中的16位紧急指针。

当URG标志位被设置为1时,需要通过TCP报头当中的16位紧急指针来找到紧急数据,否则一般情况下不需要关注TCP报头当中的16位紧急指针。
16位紧急指针代表的就是紧急数据在报文中的偏移量。
因为紧急指针只有一个,它只能标识数据段中的一个位置,因此紧急数据只能发送一个字节 

PSH 督促对方尽快将你的接收缓冲区当中的数据交付给上层。

我们一般认为:

当使用read/recv从缓冲区当中读取数据时,如果缓冲区当中有数据read/recv函数就能够读到数据进行返回,而如果缓冲区当中没有数据,那么此时read/recv函数就会阻塞住,直到当缓冲区当中有数据时才会读取到数据进行返回。
实际这种说法是不太准确的,其实接收缓冲区和发送缓冲区都有一个水位线的概念。


比如我们假设TCP接收缓冲区的水位线是100字节,那么只有当接收缓冲区当中有100字节时才让read/recv函数读取这100字节的数据进行返回。
如果接收缓冲区当中有一点数据就让read/recv函数读取返回了,此时read/recv就会频繁的进行读取和返回,进而影响读取数据的效率(在内核态和用户态之间切换也是有成本的)。
因此不是说接收缓冲区当中只要有数据,调用read/recv函数时就能读取到数据进行返回,而是当缓冲区当中的数据量达到一定量时才能进行读取。
当报文当中的PSH被设置为1时,实际就是在告知对方操作系统,尽快将接收缓冲区当中的数据交付给上层,尽管接收缓冲区当中的数据还没到达所指定的水位线。这也就是为什么我们使用read/recv函数读取数据时,期望读取的字节数和实际读取的字节数是不一定吻合的。

RST 要求重新连接的标志位

在通信双方在连接未建立好的情况下,一方向另一方发数据,此时另一方发送的响应报文当中的RST标志位就会被置1,表示要求对方重新建立连接。
在双方建立好连接进行正常通信时,如果通信中途发现之前建立好的连接出现了异常也会要求重新建立连接。 

3. 3次握手和4次挥手

(1)什么是链接

因为有大量client将来可能会连接server,所以server端一定有大量的连接,OS将这些连接管理起来,先对这些连接的共性和差异进行描述刻画,再将他们通过一定的结构组织起来。

所谓的连接,本质是内核中的一种数据结构类型,建立连接成功的时候,内存中会创建对应的连接对象,在对对象进行某种数据结构的组织。

==》维护连接实惠消耗CPU和内存资源的!!!

(2)如何理解3次握手

      为什么要三次握手?不可以是一次,两次吗?

  1.奇数次连接可以保证server端 嫁接同等程度的成本给client端,(避免大量的SYN洪水造成server端不能正常工作);

           2.可以很好的验证全双工。

分析如图:

      建立连接一定能成功吗?

  如图,第三次的ACK是可能会丢失的,所以三次握手不一定保证成功,这就会涉及到之前提到的 RST和PSH 标志位了。

(3)如何理解4次挥手

TIME_WAIT状态下,虽然4次挥手已经完成,但是主动断开连接的一方要维持一段时间(2MSL 最大报文生存时间,保证数据在网络中消散)的TIME_WAIT,在该状态下,连接实际已经断开但是地址信息,ip,port依旧是被占用的,此时就可能出现bind失败的情况。

如果我们发现服务器具有大量的CLOSE_WAIT状态的连接,原因是什么呢?

    应用层的服务端写的有bug,忘记关闭对应连接的sockfd。必须主动将不需要的文件描述符关闭

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

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

相关文章

【技巧】如何保护PDF文件不被随意修改?

做好的PDF文件,不想被他人随意修改,只要给PDF设置“限制保护”就可以了,设置保护后需要输入密码才能进行编辑。 设置“限制保护”我们需要用到PDF编辑器,以小编使用的编辑器为例,首先通过编辑器打开PDF文件后&#xf…

【前端】WebWorker 在前端SPA框架的应用

一、什么是WebWorker 概念: Web Worker是一种在Web浏览器中运行的JavaScript脚本,它可以在后台线程中运行,而不会阻塞主线程。这意味着Web Worker可以在后台执行复杂的计算任务,而不会影响用户界面的响应性能 除了标准的JavaScri…

使用TCP方式拉取Canal数据

1 Canal对接Kafka联调 1.1 配置修改 canal.properties 修改 zk: canal.zkServers 10.51.50.219:2181instance.properties 开启配置项: canal.mq.dynamicTopic 是 Canal 的 MQ 动态 Topic 配置项: test_javaedge_01 是kafka 的 topicte…

golang面试题:json包变量不加tag会怎么样?

问题 json包里使用的时候,结构体里的变量不加tag能不能正常转成json里的字段? 怎么答 如果变量首字母小写,则为private。无论如何不能转,因为取不到反射信息。如果变量首字母大写,则为public。 不加tag&#xff0c…

00_socket_demo

1.服务器端的代码 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h>#define PORT 8080 #define BUFFER_SIZE 1024int main() {int server_fd, new_soc…

STC8单片机PWM定时器+EC11编码器实现计数

STC8单片机PWM定时器+EC11编码器实现计数 📌相关篇《STC单片机+EC11编码器实现调节PWM输出占空比》📍《stc单片机外部中断+EC11编码器实现计数功能》🔖STC8系列支持此功能的型号: ✨从上面的相关篇中有通过通用定时器加外部中断以及常规方法实现驱动EC11编码器的方法。本…

Consul学习笔记之-初识Consul

文章目录 1. What is consul?2. Consul能干什么3. Consul的架构3.1 概念 4. Consul VS Eureka4.1 CAP4.2 对比 1. What is consul? 根据官方文档的定义&#xff1a; HashiCorp Consul is a service networking solution that enables teams to manage secure network connec…

觉非科技数据闭环系列 | BEV感知研发实践

随着自动驾驶迈向量产场景&#xff0c;“BEV感知数据闭环”已成为新一代自动驾驶量产系统的核心架构。数据成为了至关重要的技术驱动力&#xff0c;发挥数据闭环的飞轮效应或将成为下半场从1到N的胜负关键。 觉非科技在此方面已进行了大量的研究工作&#xff0c;并在实际量产项…

vuex中actions异步调用以及读取值

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 将根据segmentId查出来的合同信息托管到vuex中&#xff0c;让每个人都可以获取到合同信息 描述以及问题点 1&#xff1a;调用vuex异步函数的语法是 this.$store.dispatch(actions方法名,值) 2&#…

typeScript 学习笔记(二)

类接口 TypeScript 入门教程 (xcatliu.com) 十四.类 ① 类 类&#xff1a;定义了一件事物的抽象特点&#xff0c;包含它的属性和方法对象&#xff1a;类的实例&#xff0c;通过new生成面向对象&#xff08;OOP&#xff09;的三大特性&#xff1a;封装、继承、多态封装&…

arm栈推导

按照栈生长方向分&#xff1a;可以分为递增栈&#xff08;向高地址生长&#xff09;&#xff1b;递减栈&#xff08;向低地址生长&#xff09; 按照sp执行位置来分&#xff1a;满栈&#xff08;sp指向栈顶元素的位置&#xff09;&#xff1b;空栈&#xff08;sp指向即将入栈的…

ChatGPT AIGC总结Excel中Vlookup,lookup,xlookup的区别

在Excel的使用过程中,查找函数是非常重要的,如Vlookup,lookup,Xlookup,index+match等都是使用的最多的函数,我们让ChatGPT,AIGC用思维导图来总结一下,各查找函数的用法与区别。 AIGC ChatGPT ,BI商业智能, 可视化Tableau, PowerBI, FineReport, 数据库Mysql Oracle…