TCP传输控制层协议深入理解

Hello!!大家早上中午晚上好!今天来分享一下对于TCP传输控制层协议的理解、总结!!

一、什么是TCP

1.1 TCP是传输层协议的其中一种
1.2 什么是传输层?在哪里?

图解(以Linux系统为例):

TCP(Transmission Control Protocol),正如它的名字一样,传输控制协议,就是用来控制数据的传输的!!

1.3 TCP如何控制传输?在哪控制?控制什么?如何控制??

画图理解TCP数据传输的整个过程:

①、主机A从用户缓冲区通过系统调用接口把数据拷贝到传输层中的发送缓冲区里;

②、主机A通过网络把发送缓冲区里的数据拷贝到主机B的接收缓冲区内;

③、主机B通过系统调用接口把数据从接收缓冲区拷贝到用户缓冲区,获取到数据;

④、主机B处理数据后把结果通过系统调用接口从用户缓冲区拷贝发送缓冲区;

⑤、主机B把发送缓冲区里的数据通过网络拷贝到主机A的接收缓冲区;

⑥、主机A通过系统调用接口把数据从接收缓冲区里读到用户缓冲区,获取到结果;

以上就是TCP数据传输的整个过程,因为TCP拥有两个缓冲区,一个读一个写,因此TCP是全双工的传输协议(支持同时读写!)

**在这最关键的问题是:**发送缓冲区里的内容什么时候发?发到哪里?发多少?在网络中发送失败了怎么办??这些一系列问题都是通过TCP协议自主决定的,也就是所谓的传输控制!!

二、认识TCP协议段格式(报头)

2.1、什么是协议?

协议就是双方的一种约定,为什么两个人说话双方能听得懂?因为双方规定了:"你好"、"吃饭了吗?"代表什么意思;

同理TCP协议,两台主机在传输层中双方规定了当接收到xxxxxxxxx时代表什么意思,所以双方能够通信!!!

这里的xxxxxxxxxxxxx就是TCP协议段,即报头!!所以我们来认识以下TCP的报头吧!!

TCP协议为什么报头有这么多内容?因为TCP协议的特点就是保证数据传输的可靠性,即对数据发送后出现的各种问题都有它的应对处理方法,所以报头里的各个字段必不可少(就像你寄个快递,你必须填写你的姓名手机号从哪里寄出去,寄到哪个地址,这些内容必不可少!)

三、报头的各个字段的理解

3.1、源端口号&&目的端口号的作用

我们知道当我们发送一个数据给对方的时候是要从应用层->传输层->网络层->数据链路层->物理层一层层往下传,直到传送到网卡,然后从网卡经过路由器发送到对方的网卡;

然后对方从物理层(网卡)->数据链路层->网络层->传输层->应用层,才到达对方用户手上;

所以这里的源端口号代表的是发送方从哪一个端口发出,目的端口号代表的是接收方的哪一个端口接收,用来决定从哪发出并向上交付给谁

3.2、TCP序号&&TCP确认序号的作用:

如果我们发数据是这样发的:

如果我们发送数据是这样发的:

很明显这两种方法第二种效率会大大的提高,那么问题来了:Client一次发送多个数据,由于数据在网络中传输的时候经过层层设备,在这个途中的不确定因素非常多,万一某个设备出现故障了呢?万一突然失去网络信号了呢?这样导致的结果就是:无法保证Server依次接收到的是Client依次发送出去的数据,例如:Client发送顺序是1、2、3、4,Server接收顺序是3、1、2、4,这就是数据传输中出现的乱序问题,导致的结果是想接收的内容跟对方发送的内容对不上,乱序本身就是不可靠的一种!那么TCP要如何保证传输的可靠性呢?

TCP报头中的32位序号:

我们知道在内核中发送缓冲区就是一个数组,数组天然拥有数组下标,我们用即将发送的数据块的最后一个字符的下标作为TCP报文中的32位序号来标记这个数据的序号!!用这个序号+1表示确认序号!!

什么意思呢?

图解:

为什么要用两个序号?直接用一个序号不行吗?

如图,当我们捎带应答的时候,必须把两个序号分开,不然无法确定这个序号是对上一个请求的确认还是对当前请求的确认;

3.3、四位首部长度的作用:

用来标记整个报头的长度:即标准报头20个字节+选项的长度,选项的长度最大为40字节:

当选项为0时,整个报头的长度为20,也就是首部长度表示的最小长度为20字节,首部长度在计算的时候单位是4字节,也就是首部长度(4位)*4字节=20字节,即首部长度最小为5,即0101;

最大长度为1111,即15*4=60字节=标准报头+选项长度,所以选项长度最大为40!

3.4、六个标记位的作用:

当我们建立连接的时候需要发送报文、当我们断开连接的是时候需要发送报文、当我们发送数据的时候需要发送报文。。。所以为了区分这些报文是要干嘛的,也就是把这些报文归类,所以标记位起到了作用,可以根据标记位把一个个报文分成不同的类型;

①、ACK标志位:确认号是否有效(用来对上一个报文的确认):

例如:

②、SYN标志位:请求建立连接,同步报头文;

双方通信之前需要建立连接,建立连接的时候发送的就是SYN报文,例如双方通信时的三次握手:

③、**FIN标志位:**用来通知对对方,本段要关闭了;

用于四次挥手断开连接:如图:

④、PSH标志位:用来提示接收端应用程序立刻把TCP缓冲区的数据读走;

当TCP接收缓冲区快满的时候,可以发送PSH报文用来告知对方立刻读走数据腾出空间,图解:

⑤、**RST标志位:**对方要求重新建立连接,复位报文段;

作用如图:

⑥、**URG标志位:**紧急指针是否有效;(当设为1,表示该报文中涵盖了紧急数据,16位紧急指针指向数据偏移量位位置);

作用:

TCP报文里有一个16位紧急指针,这个16位数字写的是数据从开始往后的偏移量,如图:

紧急指针指向大小为1字节的空间,然后往后当用户接收到URG标志位的报文时,读取数据会先从紧急指针指向的位置开始读取!这种数据称为带外数据!!

3.5、16位窗口大小

16位窗口大小填写的是自己当前的接收缓冲区所剩空间的大小;

四、TCP协议的策略

TCP通信为了保证双方通信时数据的可靠性,TCP设置了非常多的策略,以至于用来解决双方通信过程中会出现的一系列问题:例如数据传输在途中丢失怎么办?例如对方主机出现问题无法接收怎么办?例如突然间断网怎么办?例如对方空间不足接收不了这么多数据怎么办?等等;

同时TCP通信为了保证双方通信时数据传输的效率,也设置了非常多的策略,可以让双方的数据传送更快更多效率更高!!

4.1、超时重传机制

如图:

我们要明确一点是:当Client发送数据后,Client对自己发送的报文是否丢失无法判断的!必须通过规定来表征!!

**因此我们规定:**当发送数据后,在特定的时间段内如果没有收到ACK应答报文,那么我们认为这个数据已经丢失(虽然这个数据可能还存在于网络中,或者已经发送给对方了)!!这时就会触发超时重传机制,对报文进行重发,当Server收到相同的报文时,Server会对报文进行去重,然后再发送ACK报文确认;

这个特定的时间如何设置?设置多少合适?:

**①、**在Linux以500ms为一个单位进行控制,每次判断都是500ms的整数倍;

②、 例如第一次等待了500ms没收到响应对报文重传;

③、 第二次还没收到响应,这次判断的时间为2*500ms;

④、第三次还没收到响应,这次判断时间为4*500ms;

⑤、累计超过一定的重传次数断开连接;

可以看出,每次判断的时间是以指数级递增;

4.2、理解三次握手跟四次挥手(连接管理)

①、什么是三次握手?

引用上图,三次握手是两台主机在通信之前双方必须要做的事,即双方建立连接!

②为什么是三次不是四次不是5678次?

因为:1、因为一般客户端跟服务器的比例都是n:1,一般都是多个客户端而少量服务器,所以一般都是客户端向服务器发起连接,然后奇数次可以保证把建立连接失败的代价嫁接在客户端;

2、三次握手其实是在四次握手的基础上优化了,把第二次握手时捎带应答,把原本需要发送两次报文(一个ACK,一个SYN)变成发送一次,一次发送的报文中包含对上一个报文的确认和对Client建立连接的报文;如图:

3、因为三次握手的时候可以在建立连接的同时验证双方的全双工通道是否畅通,如图:

4、三次握手后当Client发送ACK报文后就代表双方已经建立好连接,不管ACK报文Server是否收到!Client就可以开始给Server端发送数据了,如果Server没收到ACK报文,Server会在Client发送数据时给它响应一个RST重连报文;

③、什么是四次挥手

引用前面的图:

四次挥手就是Client向Server发送FIN报文,Server向Server响应ACK报文,然后Server向Client发送FIN报文,最后Client向Server发送ACK报文;

④、为什么是四次挥手而不是5678次?

因为:1、这里的二三次挥手中并不是每次都能捎带应答,因为在很大的几率上当Client向Server发起断开连接时,Server端还有数据没处理完成的,需要等待的需要维持一段时间的。所以ACK响应报文跟FIN断开连接报文是要分开的,先响应Client的断开请求,然后再确然自己确确实实把所有数据处理完了,然后再发送FIN报文!这样做的目的是为了保证双方的数据都已发送完毕;

⑤、理解四次挥手中的TIME_WAIT状态

主动断开连接的一方会有一段时间处于TIME_WAIT状态,处于这个状态中会等待若干时间后才会自动释放,如果是Server方,连接没有被彻底断开,ip和port正在被使用,无法立即重启,所以我们设置的

int opt=1;

setsockopt(listensockfdSOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt)就是为了防止服务器异常挂掉后无法立即重启;

而客户端为什么不会呢?因为客户端的端口号是系统给的,每一次都是随机的,所以不会;

为什么要这么做呢?为什么要TIME_WAIT等一段时间呢?

因为:1、让通信双方的历史数据得以消散;

2、让我们断开连接的时候4次挥手中具有较好的容错性;

⑥理解三次握手中的ESTABLISHED和SYN_RECV状态

理解SYN_RECV状态就要先理解再socket套接字创建时,listen接口的第二个参数:backlog

如图,我们发送的连接请求是先进入到全连接队列里等待,如果全连接队列满了会被放进半连接队列,当上层从全链接队列里取走后有空位了才会进入到全连接队列;

backlog设置的就是全连接队列里能容纳的最大连接的个数,当全连接队列满了的时候再进来的连接会到版链接队列里等待,这个时候server端会把再接收到的ACK报文丢弃掉让自己处于 SYN_RECV状态,这是一个临时状态,表示全连接队列满了当前正处于半连接队列中等待着 ;

如图:

这个时候Client处于ESTABLISHED状态而Server出于SYN_RECV状态表示双方建立连接不一致,后续Client发送数据的时候,Server会给Client发送RST报文让Client重新连接;

4.3、流量控制

①、什么是流量控制?

TCP根据双方的接收端的接收能力来控制发送端的发送速度;

②、怎么实现的流量控制?

在双方第一次建立连接时互发的报文中的16位窗口大小,双方已经协商了接受能力!

然后通过滑动窗口实现流量控制;

4.4、滑动窗口

①、滑动窗口在哪里?

滑动窗口存在发送缓冲区,是发送缓冲区的一部分;

②、发送缓冲区里有什么内容?

发送缓冲区中包含:1、已发送已确认的报文,这部分内容是可以被覆盖的;2、已发送未确认的报文,这部分报文被暂时保存在发送缓冲区;3、待发送的报文;

③、滑动窗口是什么?

滑动窗口用双指针维护,一个指针指向开始,一个指针指向结束,通过对双指针的移动从而实现像窗口一样滑动;start=根据确认序号设置,end=确认序号+win大小(确认报文中对方的窗口大小)

4.5、快重传

快重传的概念:

当某个发过来的请求丢了的时候,server响应会一直卡在这个请求序号的前一个序号中,会重复应答3次前一个序号,当Client连续收到三个同样的序号的时候会立即对该序号进行重发;

如图:

4.6、延迟应答

延迟应答是在收到报文之后不着急应答,让上层有更大的概率把数据从缓冲区中取走,但是上层不一定会取走,这是一个博概率的策略,目的是为了给对方通知一个更大的窗口,让对方可以发送更多的数据,这是一个提升效率的策略;

4.7、拥塞控制

1、如果我们发送数据的时候出现少量的丢包,我们认为是对方的问题;

2、如果我们发送数据的时候出现大量的丢包(有大量的超时重连),我们认为是网络问题(出现网络拥塞了);

当我们出现网络拥塞的时候:对这批大量的丢包不能立即重发,因为这样只会加重网络拥塞,

我们采取的策略是:慢启动!即先向网络发送少量报文,当正常的时候逐渐发送更多的报文,

当我们连续发送报文都ok的时候说明网络已经趋于健康了,应该尽快恢复正常通信!

慢启动的阈值: 最近一次发生网络拥塞时,拥塞窗口大小/2;

拥塞窗口: 用来表面网络的健康状态,超过拥塞窗口会引发网络拥塞,否则不会,网络是动态的,拥塞窗口也是动态的!

所以:我们一次能给对方发送多大的数据取决于对方的接收能力+网络的拥塞程度;

具体的说:滑动窗口=min(对方窗口(对方接受能力),拥塞窗口);

什么意思呢?

就是当对方的接收能力很强的时候(对方窗口很大),但网络一般(拥塞窗口很小),这时候滑动窗口==拥塞窗口;

当对方接受能力很差(对方窗口很小),但网络很好(拥塞窗口很大),这时候滑动窗口==对方窗口;

注:滑动窗口可以用来表示双方数据在网络中通信的时网络吞吐量;

五、理解面向字节流

5.1、什么是面向字节流?

读写双方不需要完全匹配:

例:1.写100字节可以调用1次write写100字节,或者调用100次write写1字节;

2.读100字节可以调用1次read读100字节,或者调用100次read读1字节;

可以与UDP对比:每次写100字节调用一次write,对方必须只能一次调用read读100字节,不能调用10次read读10字节!!

Tcp协议是一个面向字节流的协议,Tcp通信在数据传输的过程中Tcp不关心上层协议,Tcp只认识字节,至于一次读多少完全由用户层决定,且对读上来的数据需要用户自己处理获取报文,所以获取到的数据可能不是一个完整的报文!!

5.2、粘包问题

由于TCP是面向字节流,我们读多少数据由用户自己决定,所以读上来的可能不是一个完整的报文,可能多出来也可能少了一部分,如图:

所以用户层需要自己设计Encode(封包),Decode(解包)自己订协议,让自己能够获取到一个完整的报文;

5.3、如何定制协议解决用户层的粘包问题?

①、定长报文;

②、特殊字符;

③、定长报文+自描述字段;

④、特殊字符+自描述字段;

总之:只要能够明确报文与报文之间的边界!!

六、TCP异常情况

**当机器断电、重启、网线断开的时候:**让连接进行4次挥手即可!

七、总结

TCP为了保证双方在网络通信中能够更高效更安全地进行数据之间的传输提供了上面的一系列策略,这些所有策略都是作用在两台机器上,TCP对于网络中出现的问题是无能为力的,就像那句话"万事俱备,只欠东风",东风指的就是网络策略再周到没有网络信号啥也不是!

总结以上策略,TCP给通信双方提供的可靠性的策略有:

· 校验和

· 序列号(保证按需到达/可以通过序列号去重)

·确认应答(核心)

·超时重传

·连接管理

·流量控制

·拥塞控制

为双发传输数据提高性能的有:

· 滑动窗口

· 快速重传

· 延迟应答

· 捎带应答

好了,以上是本次分享的所有内容,如果对你有所帮助记得点赞收藏+关注哦!!谢谢!!!

咱下期见!!!

相关推荐
小小不董7 分钟前
深入理解oracle ADG和RAC
linux·服务器·数据库·oracle·dba
AA陈超33 分钟前
虚幻引擎UE5专用服务器游戏开发-20 添加基础能力类与连招能力
c++·游戏·ue5·游戏引擎·虚幻
mit6.8241 小时前
[Meetily后端框架] AI摘要结构化 | `SummaryResponse`模型 | Pydantic库 | vs marshmallow库
c++·人工智能·后端
狄加山6751 小时前
Cadence模块复用
服务器·硬件架构·硬件工程·信号处理·智能硬件
screenCui1 小时前
macOS运行python程序遇libiomp5.dylib库冲突错误解决方案
开发语言·python·macos
R-G-B1 小时前
【02】MFC入门到精通——MFC 手动添加创建新的对话框模板
c++·mfc·mfc 手动添加创建新的对话框
宇钶宇夕1 小时前
SIMATIC S7-1200的以太网通信能力:协议与资源详细解析
运维·服务器·数据库·程序人生·自动化
该用户已不存在1 小时前
关于我把Mac Mini托管到机房,后续来了,还有更多玩法
服务器·前端·mac
linux kernel1 小时前
第七讲:C++中的string类
开发语言·c++