网络原理2 TCP协议

news2024/12/28 5:03:56

TCP协议

文章目录

  • TCP协议
    • TCP的特点
    • TCP的基本特性
      • 确认应答机制
      • 超时重传机制
        • 丢包
      • 连接管理机制
        • TCP建立连接---三次握手
        • TCP断开连接---四次挥手
      • 滑动窗口机制
        • 丢包问题
      • 流量控制机制
      • 拥塞控制机制
      • 延迟应答机制
      • 捎带应答机制
      • 面向字节流问题
    • TCP中的异常处理
      • 程序崩溃了
      • 正常关机
      • 突然断电关机
        • 掉电的是接收方
        • 掉电的是发送方
      • 网线断开
    • TCP与UDP的比较

在传输层中,UDP和TCP协议都是很重要的,其中的TCP协议是重点,更是难点。

TCP的特点

有连接

可靠传输

面向字节流

全双工(信号能进行双向传输)

image-20221211144046809

首部长度(4bit): 描述TCP报头有多长,表示范围是0 - 15(0000 - 1111)

image-20221211145039507

6个标志位,后面再说

上面报文格式中很多的属性并没有解释,此时不好解释,会在后面进行一一解释

TCP的基本特性

面向字节流 有连接 全双工 都是能在代码中体现的,可靠传输是TCP中最核心的特性,但是TCP是如何保证可靠传输的?

所谓的可靠传输是指当发送方发送之后,发送方知道自己是否发送成功

确认应答机制

收到消息的一方给出应答,给出的应答就叫确认应答, 也叫ACK应答(acknowledge)

image-20221212103806434

对于普通报文,ACK是0

对于应答报文,ACK是1

确认应答机制,是TCP保证可靠性的最核心的机制

发送多条请求的时候,可能会出现后发的请求先到达的情况,主要是因为网络上通信传输的路径是很复杂的,两点之间,报文走不同的路线,所以就可能会出现后发先至的情况

后发先至是网络传输中很难避免的事情

但是我们可以将 请求和应答报文进行编号,这样就不会搞混了

所以要在确认应答机制中引入序号来避免歧义

在TCP报文中,就有这样的设计:

image-20221212105918768

上面的序列号是请求数据的编号

确认号是针对ACK报文有效,也就是只针对对应的请求数据有效

TCP是面向字节流的,所以编号的时候,也是以字节为单位,进行编号的

image-20221212110708539

一开始报文的序号是1,报文的长度是1000,所以最后一个字节的数据编号是1000,在TCP报头中只能存一个序号,最后一个字节的序号 是根据报文长度推算出来的

确认应答报文的确认序号是1001,表示的是: 之前的1000个的数据都已经收到了,现在B向A索要序号从1001开始的数据

之后A又向B发送序号为1001开始,长度为1000的数据,之后B给出确认应答,并索要2001开始的数据

image-20221212111258708

主要是想让 请求与应答 对应上

以上就是确认应答机制中的加入编号,这样就能有效的避免混淆

TCP是32位序号和确认序号,表示的数据范围也就是2^32,相当于4GB,就算是数据量很大,超出了范围,可以重头再来,只要能对应上就行了

超时重传机制

确认应答机制描述的是: 数据报顺利到达到对方,对方给出ACK响应

丢包

但是要是在传输过程中,出现了丢包,也就是请求根本没传过去,此时该怎么办呢?

首先要知道为什么会丢包

网络环境很复杂,之所以能上网,是因为接入了运营商的网络,运营商有很多路由器/交换机,同一时刻会有很多的数据报经过一个交换机,交换机的转发能力是有上限的,达到转发上限,有可能导致一部分数据超时,从而导致丢包

现在假设我要给别人发消息,要是我的报文丢了,或者他给我的响应报文(ACK)丢了,都会触发超时重传

超时重传机制通过设置一个超时时间,来检测数据包是否发送成功。如果在超时时间内没有收到确认信息,则认为数据包发送失败,系统会重新发送这个数据包。这样,就可以有效地避免数据包丢失,提高网络传输效率。

要是是我的报文丢了,只要重发一遍就行了

要是是ACK丢了,对方就会受到 两个一样的报文,此时就要考虑去重了

在TCP协议中,接收方因为丢失ACK导致受到相同的信息,TCP会根据序号来去重

超时重传也能保证可靠传输

超时时间如何确定?

一般系统中会有一个配置项,描述超时的时间阈值

第一次出现丢包,发送方会在达到时间阈值之后,进行重传,要是还是丢包了,还会继续重传,但是这次的时间阈值就会变得更长

所以,时间阈值不是均等的,是一次一次变长的

主要是因为,连续多次丢包的概率比较小,极端一点就是断网了,不管怎么重传都收不到信号,所以不如将重传的频率降低一点,节省点主机的开销

要是连续多次重传都不行,就尝试重置TCP连接(断开重连),要是还是连不上,就直接释放连接(彻底放弃)

注意: 这里并没有说明 第一次重传的时间 重传失败的间隔 重传的次数,主要是因为不同的系统中是不一样的,而且也是可以配置的,所以没有必要去记住

类似的案例:

HashMap解决哈希冲突,通过链表的方式,要是链表太长了,就要把链表转换成红黑树,所以链表元素达到多少才会转换成红黑树?

这也是没必要知道的,因为不同版本的哈希表的实现方式不同,数字也就不同

连接管理机制

ACK 确认报文段

SYN 同步报文段

FIN 结束报文段

注意在TCP中,主要强调的是发送方 和 接收方

连接管理描述的是TCP建立连接和断开连接的过程

TCP的连接是让通信双方建立逻辑上的 虚拟的连接

TCP建立连接—三次握手

建立连接的过程就是三次握手

image-20221212141713273

image-20221212141756086

要是syn为1,说明这是一个同步报文段,尝试与对方进行连接

为什么要进行三次握手?建立连接的意义是什么?

  1. 三次握手并不会传输任何的业务数据,只是先检查一下网络情况是否通畅

  2. 三次握手也是在检查通信双方的发送和接收能力是否正常

    举一个简单的例子

    假设AB两个人准备一起打游戏,在打之前,要先试一下声音

    image-20221212143220579

    当B收到A的“我来了",B就知道自己的接收能力没问题,A的发送能力没问题

    当A收到B的“我也来了”,A就知道自己的接收能力没问题,B的发送能力没问题,进一步知道了,自己之前发的消息B也知道了,所以A就知道自己的发送能力没问题,B的接收能力没问题,此时A已经全都清楚了

    当B收到A的“准备开始”时 , B就知道自己的接收能力没问题,A的发送能力没问题,进一步知道了,A的发送能力没问题,自己的接收能力也没问题,此时B也全都清楚了

    3.三次握手的过程中,也能协商一些重要的参数

    两个重点的TCP状态:

    1. LISTEN : 服务器启动之后,绑定端口之后(new ServerSocket)完成之后,可以接收连接
    2. ESTABLISHED: 连接建立好之后的稳定状态(stable --> stablished,前面加个E)

为什么ACK 和 syn能合并在一起发送?

是因为在三次握手中,发送方在收到客户端的syn之后,ACK立即被触发(由内核完成的)

接收方给客户端的syn也是立即触发的(也是由内核触发的)

ACK和syn都是立即触发的,所以两者可以合并在一起

TCP断开连接—四次挥手

断开连接就是双方取消相互认同的关系,通信双方,各自向对方申请断开连接,再各自给对方回应

image-20221212153402260

这里的ACK和FIN不一定能合并

ACK是操作系统内核在收到FIN后,立即触发的

FIN是应用程序显式调用socket的close方法触发的,主要是看代码实现

所以ACK和FIN的时机不一样,所以不一定能合并

但是,TCP中还有捎带应答机制,还是有可能合并在一起的

综上,还是四次挥手比较好

image-20221212154126773

TCP的两个中重要的状态

CLOSE_WAIT: 等待代码中调用close方法

TIME_WAIT: 主动发去关闭的一方在处理完最后一个ACK之后,不能立刻释放连接,而是要保持一段时间,之后再关闭

不能直接关闭的原因是: 要是最后一个ACK没传过去,服务器就会重发一个FIN,此时客户端就会再传一个ACK

应答(ACK)和响应(response)是不一样的,ACK只是告诉对方,已收到消息,ACK是系统内核负责的,会在收到请求之后,立刻返回

响应会携带业务上的数据,由应用程序负责,取决于代码

滑动窗口机制

TCP确实有效地保证了数据的可靠性,但是效率并不高

image-20221212174341611

主要是因为发送一条请求之后,要等到ACK之后,才发下一条请求,这样就会很慢

为了能尽量提高点效率,就有了滑动窗口机制

要想提高效率,就可以每次批量发送一波消息,之后再等一波ACK,之后每收到一条ACK就再发一条数据

把不需要等待,一次能直接发送的数据量称为“窗口大小”

image-20221212174948288

批量发送4条数据,批量等待4条ACK

这里的滑动窗口是每收到一条ACK就再发一条数据,而不是收齐了所有的ACK才再发数据

要是假设窗口是无限大的,那么一次性就把所有的数据都发出去了,这样子就不用等待ACK了 ,此时效率就变得像UDP一样高了,但是不等ACK,就不可靠了,TCP也就失去了它的价值

丢包问题

丢包主要是两种情况:

  1. 发送的数据包丢了
  2. 数据到了,但是应答报文(ACK)丢了

对于ACK丢了的情况:

image-20221212181039537

要是ACK丢了,其实根本就没有任何影响

因为,大的序号是包含之前的小的序号的,所以要是前面的ACK丢了,但是只要后面的ACK还在,就说明之前的数据都到达了

举一个例子:拥有了大学毕业证,就意味着拥有了高中毕业证,这里有包含的关系

要是刚好是最后一个ACK丢了,还有超时重传,所以也没事

对于数据包丢了的情况:

image-20221212182319726

​ 一开始1001-2000数据报丢失时,A不知道的,所以A继续发数据包,B也一直向A索要1001-2000,后来A意识到丢包了,所以重传了1001 - 2000,由于A之前已经把7000的数据报都传给B了,所以此时B已经收到了7000之前的所有数据报,所以B 开始索要7001开始的数据报,后面就回归正常了

这样子,只是将丢的数据包重传了,并没有多余的操作,所以效率很高

这就叫做快速重传(搭配滑动窗口机制的超时重传)

滑动窗口的大小是不能无限大的,因为要是发的很快,很多,接收方是跟不上的,就会丢弃一部分数据,这样子TCP就不能保证可靠传输了

流量控制机制

要是发送的速度太快,可靠性就不能保证

要是发送的速度太慢,也不好

流量控制就是基于滑动窗口的基础上,对发送速率做出限制,限制发送方的窗口大小不要太大,也不要太小

至于如何把握好度,主要是看接收方

接收方根据自己的接收能力,来反向影响发送方的发送速率

接收方会根据自己的接收缓冲区剩余空间(其实就是剩下的内存),来决定发送方的速率

image-20221212203346668

接收方收到发送方的数据后,就会在ACK报文中,将当前 缓冲区剩余空间的大小的值反馈给发送方,这里的值就是报文中的窗口大小,只有在应答报文中才有效,每一个ACK传回来的窗口大小都会实时改变

image-20221212204031256

要是窗口的大小 变成0了,此时发送方就不发了 ,要是不发了,接收方就没办法返回ACK,后续接收方有空闲空间了,怎么告诉发送方可以发呢?

要是超过了超时的时间,还是没有窗口更新的通知,发送方就会发送一个窗口探测报文,这样子接收方就能返回ACK,带回来窗口大小

拥塞控制机制

但是不是只要考虑发送方和接收方,在数据传输的时候,中间还会有很多的转发节点,这些转发节点也都会影响发送的速率,所以也要考虑,但是这并不是好量化的

思路: 将中间的设备想象成一个整体,之后在不断试探 来验证 合理的发送速度, 也就是一开始发送的速率比较慢,要是一路通畅,就提速,一旦发生了丢包就降低速度,变得通畅了之后,再提高速度…动态调整

这就是在一步一步试探底线,试探出最合理的发送速度的过程

拥塞控制机制的具体实现:

首先“慢启动”,先规定一个很小的数据,开始的时候先指数增长,达到阈值之后就线性增长,一步一步寻找到最大的窗口大小

以指数增长,是为了快速摸清楚最佳的窗口大小,但是为了防止翻得太快超过上限,达到阈值之后变成线性增长

image-20221213155655819

一开始的阈值是系统规定的,当发生丢包之后,新的阈值就是刚才丢包时窗口的大小的一半,所以阈值都是动态调整的

要是新的阈值比之前窗口的一半还大,指数翻倍之后就会超过阈值

流量控制只考虑发送方和接收方,接收方来反制发送方的发送速度,来确定窗口大小

拥塞控制还要考虑中间的转发节点,来确定窗口大小

要是两者的值不一样,就会选值小的那个,这样更加保险

延迟应答机制

滑动窗口的大小是根据接收缓冲区的空余空间的大小来确定发送的数据大小

假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;

如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;

窗口越大,网络吞吐量就越大,传输效率就越高

捎带应答机制

捎带应答是基于延迟应答的基础上引入的

TCP中,只要把数据传过去,对方收到之后,就会立刻由内核

返回一个ACK报文,另外,响应的数据时程序设计负责传输的

由于这两个是在不同的时机传输的,所以不能将这两者合并起来,但是有了延时应答机制,会稍微等一下响应数据,这样子就能将ACK和响应数据合并在一起了,提高了传输效率

但是捎带应答并不是总能做到,也是由一定的偶发性,要是两个动作相隔的时间比较长,此时就不能合并了

面向字节流问题

面向字节流中存在一个很经典的问题: 粘包问题

举一个例子: 东北有一种粘豆包,只要蒸完之后,就会变成一整块,分不清单独的格式,全都粘到一起了

在TCP中,A给B发消息,B给A会消息,A的应用程序需要从接收缓冲区中读取收到的数据,由于是面向字节流的,所以A无法确定哪里到哪里是一个完整的应用层数据报

再举一个例子: A给B发消息"你想不想和我一起去吃东西?",B的回答是“想得美”,由于是面向字节流的,所以A可能将“想”当做完整响应,也有可能将“想得”当做完整响应,这些都是错误的

对于UDP,面向数据报就不会存在这个问题,它是对应着一个应用层报文

想要解决粘包问题,可以在定义应用层协议的时候,明确包与包之间的边界就行了

具体的解决粘包问题的方法有两种:

  1. 通过分隔符,比如约定使用分号来作为包结束的标识
  2. 通过指定包的长度,比如在数据报的开头位置声明长度

TCP中的异常处理

程序崩溃了

程序崩溃,操作系统会回收进程的资源,包括释放文件描述符表,这样子就相当于是调用了socket中的close,也就会触发FIN,进一步开始四次挥手,这样子其实与正常的四次挥手没什么区别,所以没事

正常关机

关机的时候,系统会强制结束所有的用户进程,和上面的进程崩溃类似,系统内核会释放文件描述符表,进一步开始四次挥手,所以也是没事

突然断电关机

由于是突然断开,所以系统根本来不及做出反应

此时就要分为两种情况

掉电的是接收方

接收方突然掉电,此时发送方还不知道,所以还会继续发送数据

但是此时发送到数据,没有ACK传回来了,发送方会触发超时重传,重传几次之后,还是无应答,就会尝试重置连接(复位报文段),也会失败,此时就只能放弃连接

掉电的是发送方

掉电的是发送方,接收方等了一段时间之后,就会发送一个“心跳包”,心跳包是周期性触发的,只是一个不携带任何业务数据的包,存在的意义就是确认一下对方是否还在。

要是对方不返回心跳包,就说明心跳遗失了,对方挂了,此时就会放弃连接了

网线断开

网线断开,也是像上面的突然断电,所以要是那两种情况

TCP与UDP的比较

首先一定要明确它们的特性

TCP是有连接 可靠传输 面向字节流 全双工

UDP是无连接 不可靠传输 面向数据报 全双工

使用场景

TCP适用于有可靠性的要求的场景

UDP适用于对可靠性要求不高,但是对传输效率要求很高的场景

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

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

相关文章

在前端解决跨域

1、环境依赖 C:\Users\cyberzhaohyvm>node -v v14.17.3 C:\Users\cyberzhaohyvm>vue -V vue/cli 5.0.4 2、在项目所在目录,安装axios 进入项目所在目录: D:\01sourcecode\10Tutorial\08Vue\17-2022-12-28-v2\elementui-demo npm install axios …

Redis单线程为什么这么快?

Redis单线程为什么这么快? 第一章 Redis单线程为什么这么快 Redis深度剖析【第一章】Redis单线程为什么这么快?前言一、Redis为什么要使用单线程,而不是多线程?单线程的优势如果Redis使用多线程:既然多线程切换存在消…

【博学谷学习记录】大数据课程-学习第一周总结

Linux服务器 对于Linux操作系统来说,其本身是一个整体,包括Linux内核、系统库和系统程序,Linux内核是其最基础的部分,它实现了对硬件资源的管理,并且提供了使用这些硬件资源的通用接口。 自1991年发布Linux内核来&…

项目实战之旅游网(十四)项目部署-Docker

为了节约资源,在生产环境中我们更多的是使用Docker容器部署SpringBoot应用, 我们要用maven里的docker插件来生成镜像并且远程连接Docker, 开启远程docker服务: # 修改docker配置文件 vim /lib/systemd/system/docker.service 把…

简阅人体姿态估计深度学习方法-simpread-Human Pose Estimation Deep Learning Approach

What is Human Pose Estimation? Human Pose Estimation (HPE) is a way of identifying and classifying the joints in the human body Human Pose Estimation(HPR 人体姿态估计)是一个对人体关节进行识别和分类的方法。 Essentially it is a way to capture a set of co…

Good Bye 2022: 2023 is NEAR C. Koxia and Number Theory

原题链接:Problem - C - Codeforces 题意: 给定一个长度为n的数组,请问是否存在一个数 x ,使得任意两个数 与满足 。若是输出 YES ,反之输出 NO 。 思路: 我们可以发现一个规律: 规律&#…

本周大新闻|沙特PIF再投Magic Leap,周融资超5.1亿美元

本周大新闻,AR方面,OVER推出众包AR地图Map2Earn;AR房产平台homeAR推扫码看房功能;苹果智能指环专利公布,支持手势和触觉反馈。 VR方面,奇遇MIX正式发布;AjnaLens将发布新XR头显;Gen…

Cartesi 2022 年 12 月回顾

查看你不想错过的更新2022 年 12 月 31 日 ,我们将继续保持高昂的建设斗志一直持续到2023年。我们在2022年年底前参加了两次编程马拉松, 并不是一次。我们将 Cartesi 的技术带给了ETH India 活动的2000 多名建设者,我们还与 SuperwomenDAO 合…

RabbitMQ消息确认

目录 1. 消息确认作用 2 开发示例 2.1 生产者确认 2.2 消费者确认 1. 消息确认作用 保证消息的可靠性主要依靠三种机制:一个是消息的持久化,一个是事务机制,一个就是消息的确认机制。 1)消息持久化 消息持久化是将消息写入…

卷径计算详解(卷径通过卷绕的膜长和膜厚进行计算)

有关卷绕+张力控制可以参看专栏的系列文章,文章链接如下: 变频器简单张力控制(线缆收放卷应用)_RXXW_Dor的博客-CSDN博客_收放卷应用张力控制的开闭环算法,可以查看专栏的其它文章,链接地址如下:PLC张力控制(开环闭环算法分析)_RXXW_Dor的博客-CSDN博客。https://blo…

双向链表的双向冒泡排序、红白蓝砾石排序、算法设计4-5

(PS:直接拿的友友zy的) 一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055qq.com Time of completion:2023.1.1 Last edited: 2023.1.1 目录 (PS:直接拿的友友zy的…

添加USB wifi驱动到RK3568

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、USB接口的wifi芯片二、使用步骤wireless tools 移植wireless tools 工具测试wpa_supplicant 移植openssl 移植libnl 库移植WIFI 联网测试总结前言 在日常开…

CTF-Web渗透(入门|笔记|工具)

php各种漏洞绕过 传送门:https://cloud.tencent.com/developer/article/2127498 php伪协议 详细博客讲解: https://blog.csdn.net/cosmoslin/article/details/120695429 http://hummer.vin/2022/05/10/PHP%E4%BC%AA%E5%8D%8F%E8%AE%AE/ https://ww…

Codeforces Round #833 (Div. 2)

题目链接 A. The Ultimate Square 题意: 给你一个n,表示有n块砖,第i块砖是1*(i/2),这里是上取整,问你最大能组合成的正方形的边长是多少 思路: 观察样例就会发现是n/2上取整,下面看代码&…

快速了解网络原理

作者:~小明学编程 文章专栏:JavaEE 格言:热爱编程的,终将被编程所厚爱。 目录 局域网和广域网 局域网 局域网组建的方式 广域网 网络通信基础 IP地址 端口号 协议 什么是协议 协议分层 分层模型 OSI七层模型 TCP/IP…

Python解题 - CSDN周赛第18期 - 又见背包

卧床一周,一觉醒来,恍如隔世,做什么事都提不起兴趣,也不知道这算不算后遗症。 本期的题目还是比较简单的,也有几道做过的题。最后一道照搬过来的背包题也是比较经典的01背包了,整体感觉没有什么值得说的&am…

linux常用命令(四)- 文件备份解压缩

查看压缩文件信息 - zipinfo zipinfo命令用于列出压缩文件信息。 语法 zipinfo [-12hsvz][压缩文件]-1 只列出文件名称。-2 此参数的效果和指定"-1"参数类似,但可搭配"-h",“-t"和”-z"参数使用。-h 只列出压缩文件的文件名称。-s…

c++11 标准模板(STL)(std::deque)(四)

定义于头文件 <deque> std::deque 元素访问 访问指定的元素&#xff0c;同时进行越界检查 std::deque<T,Allocator>::at reference at( size_type pos ); const_reference at( size_type pos ) const; 返回位于指定位置 pos 的元素的引用&#xff0c;有边…

如何在PVE(Proxmox)中安装OpenWrt软路由?

出处&#xff1a; https://www.928wang.cn/archives/1763.html https://blog.itwk.cc/post/pve_install_openwrt.html 工具准备 WinSCP或者XFTPOpenWrt镜像(自行寻找)安装好PVE的主机一台 安装教程 镜像上传 将下载好的OpenWrt img镜像上传到 PVE主机中(这里使用XFTP工具) 选…

MySQL中的DDL、DML、DCL、DQL

SQL分类 DDL(Data Definition Language)数据定义语言 用来定义数据库对象&#xff1a;数据库&#xff0c;表&#xff0c;列等。关键字&#xff1a;create, drop,alter 等 DML(Data Manipulation Language)数据操作语言 用来对数据库中表的数据进行增删改。关键字&#xff1a;i…