当前位置: 首页 > article >正文

【网络】传输层协议TCP

目录

四位首部长度

序号

捎带应答

标记位

超时重传机制

连接管理机制(RST标记位)

三次握手及四次挥手的原因


TCP的全称是传输控制协议(Transmission Control Protocol),也就是说,对于放到TCP发送缓冲区中的数据,如何发,什么时候发,出错了怎么办,这些都是有TCP协议控制的

下面是TCP报文的基本格式

标准报头是20个字节,并且在传输层,并不会像我们在应用层一样还需要序列化,传输层直接发送的就是结构化的数据,因为这样发送成本是最低的,发送带宽最小。那它不是会有跨平台,大小端的问题吗?Linux内核中对它进行了处理:

不同的客户端都同时可以基于TCP协议向服务器发送信息,那么OS中就会存在很多收到的报文,这些报文可能正在网络层或数据链路层中,还没有拷贝到传输层的接收缓冲区,可能就在缓冲区中,还没来的及处理,总之各种情况

那么OS就要对大量的已经收到的,但是暂未处理的报文进行管理,如何管理呢?先描述再组织

而描述这种报文的结构体就叫做struct sk_buffer,它里面存有指针,就指向存着报文的内存空间,对于每层协议来说,报头在前面,正文在后面,我们如果要剥离报头,只需要指针向后移动一定的字节数即可,添加报头就是向前移动。所以封装与解包本质就是指针移动,然后进行一定操作

四位首部长度

那下面来解释一下TCP报文中的4位首部长度:

这个长度指的是报头的20个字节加上选项的长度,并且基本单位是为4字节

也就是说4位能表示的最大数字是15,即报头+选项的最大长度是15*4=60字节,选项的范围是[0,40]

我们都说TCP协议是可靠的,它保证可靠性,具体体现是什么呢?

因为我们发到网络中的消息,我们根本不知道它去了哪里,我们如果想知道它有没有被对方收到,就只能看有没有收到应答

所以我们可以确定的是如果我收到应答,那么我发的消息对方肯定收到了。这依靠的就是确认应答机制:我收到了消息就要应答

所以可靠性是指:我能知道对方收到了我发的消息,同时我也得知道对方没收到我发的消息

发送数据和应答这些细节其实都是双方OS完成的,这也就是“传输控制协议”中“控制”的一个体现

序号

我们发送数据可以串行发,也就是发送一条等应答,然后再发下一条等应答……,但是这样效率太慢了

我们可以一次发多条,但是问题就来了,对方也给我很多应答,那如果有一条消息对方没收到,那我怎么知道是那一条消息呢?并且对方怎么判断那条消息在前,那条消息在后呢?(因为我的发送顺序并不一定是对方的接收顺序)

这个问题的解决方法就是报头中的序号,我们可以给消息带序号,对方收到了一堆消息也可以通过排序序号来知道我发的消息的顺序,然后再按顺寻处理数据即可,所以应答就要把确认序号带上,这个确认序号一般是发来消息的序号+1

确认序号的含义就是该确认序号之前的数据,对方已经全部收到了,下次发送请从确认序号开始

我们知道TCP是有发送缓冲区,并且TCP是面向字节流的,其实我们可以把这个缓冲区看成一个一定长度的char数组,那么缓冲区中每个字节其实都有自己的序号,这个序号就是下标,确认序号我们前面说就是发来的报头中的序号+1,那么新的序号其实就是确认序号+我要发送的报文的长度

捎带应答

TCP是支持全双工的,既要向对方发送消息,也要向对方发送应答,所以需要序号和确认序号两个

如果只发应答,只需要发一个报头(报头中添加确认序号)即可,那么我可不可以发送一个报文,其中既有应答(确认序号),又有我想给对方发的数据(序号和正文)呢?当然可以,我们叫做捎带应答

标记位

下面我们来解释TCP报头中的标志位:

为什么要有标志位呢?其实就是区分不同的TCP报文类型

就比如我们知道基于TCP通信时,客户端要connect服务器,这是发的报文就是建立连接的报文,同时还有正常通信的报文,还有close时断开连接的报文等等,这些报文类型都不同,那么为了区分这些报文类型,就有了标志位

下面我们简单通过三次握手这个过程来介绍三个标记位:ACK(确认标记位),SYN(同步标记位),FIN(断开连接标记位)

这个过程是我们在客户端调用connect后OS自动完成的,首先客户端向服务器发送带SYN标记位(即将此位 置为1)的报头,服务器收到后向客户端发送SYN+ACK的报头,客户端收到后向服务器发送ACK的报头,至此三次握手成功后服务器accept获取连接。我们将服务器置为监听状态是因为只有listen状态的服务器才能受理SYN的请求

双方建立好连接之后是要对这个连接进行管理的,用内核数据结构去管理,,这样就会消耗内存空间和时间。所以说维护连接是有成本的

下面是四次挥手的大致过程:这个过程也是OS自动完成的

先调用close的一方(A)要向对方发送FIN请求,对方(B)收到后会发送ACK,之后B会发送FIN请求,A收到后发送ACK

超时重传机制

这个机制其实在报头中是没有体现的,当我们向对方发送请求时,如果我们迟迟都收不到应答,我们只能主观的认为对方没收到数据(也有可能收到了,只不过对方的ACK可能没发过来,我们肯定要按最差情况处理),此时,我们就认为超时了,我们需要重传。

也就是说,如果我们发送的请求在一个时间段内都没有收到应答,就要触发超时重传机制。

那万一对方收到了呢?只不过是ACK没发过来,因为报头中是有序号的,对方可以根据这个序号进行去重

上面说一个时间段内,那这是多少时间呢?

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

Linux,超时以500ms为一个单位进行控制,等待时间以此是1*500,2*500,4*500,这样以指数形式递增,累积到一定的重传次数,TCP就会认为网络或对端主机出现异常,强制关闭连接

连接管理机制(RST标记位)

有这样一种情况,就是三次握手的第三次ACK发送之后丢掉了,这时客户端已经认为建立好连接了,但是服务器却没有建立好连接。

此时客户端都可以向服务器发送数据了,此时服务器因为没有建立好连接但是收到了数据,此时就会向客户端发送带有RST标记位的报头来表示reset(重置),即重新进行三次握手

所以RST这个标记位就是用来解决建立连接出现异常的问题的

三次握手及四次挥手的原因

三次握手:

如果一次就可以握手,那太扯了,因为客户端连应答都没有收到,连最基本的网络连通性都无法确认

两次的话服务器是比客户端先建立连接的,维护连接是有成本的,如果客户端是恶意连接的,疯狂发送SYN请求(SYN洪水攻击),那么服务器资源就会被浪费,从而导致真正想连接的用户无法连接

所以三次握手就是因为:

1.需要保证网络(信道)是健康的,三次握手,客户端服务器双方都会有一次确定的收发,他们就可以确认是全双工

2.确保双方OS是健康且愿意通信的

四次挥手:

它的原因其实和三次握手是一样的,关键就是四次挥手没有进行捎带应答,因为虽然比如客户端关闭连接,但是服务器还有消息要发。那么此时用户如何拿取数据呢?

首先一般应用层代码是有逻辑的,一般按照协议收完消息后才会close;其次,其实我们可以仅关闭写端,不关闭读端,是有这样的接口的

如果选项是SHUT_RDWR,就相当于close


http://www.kler.cn/a/378114.html

相关文章:

  • 微服务架构面试内容整理-领域驱动设计(DDD)
  • 使用JdbcTemplate 进行数据库的增、删、改、查
  • 富格林:拆穿欺诈套路平稳出金
  • 【Linux】进程间通信(匿/命名管道、共享内存、消息队列、信号量)
  • [Prometheus学习笔记]从架构到案例,一站式教程
  • Rocky Linux 9安装后无法远程ssh密码登录解决
  • 甄选学习平台 优化员工培训体验
  • huggingface利用bert-base-chinese实现中文情感分类
  • Jenkins面试整理-如何在 Jenkins 中配置构建任务?
  • 新生代对象垃圾回收如何避免全堆扫描
  • 70B的模型需要多少张A10的卡可以部署成功,如果使用vLLM
  • 基于 Java 语言双代号网络图自动绘制系统
  • Vue 事件阻止 e.preventDefault();click.prevent
  • 使用GraphQL构建高效API
  • ArcGIS API for JavaScript 基础应用+实例展示+水波纹特效
  • SpringBoot整合minio服务
  • windows下用CMake构建使用protobuf的应用,编译使用VS2022
  • LeetCode 3226. 使两个整数相等的位更改次数
  • UML介绍-不同类间关系
  • 【Linux】从零开始使用多路转接IO --- poll
  • 利用 Direct3D 绘制几何体—8.光栅器状态
  • 刘艳兵-DBA021-升级到Oracle Database 12c时,关于使用Export/Import方法迁移数据的说法是正确的?
  • 第三次RHCSA作业
  • 【vue】11.Vue 3生命周期钩子在实践中的具体应用
  • 《JVM第1课》Java 跨平台原理
  • qt QScrollArea详解