1.前言
其实TCP协议
所在的传输层
是一个在网络系统里很基础的层级了,模组中常用的HTTP,MQTT,FTP都是在TCP的基础上建立起来的,如果TCP不能用,以上这样应用都要凉凉。
2.TCP协议
前面的《网络协议1协议栈》已经简单的介绍了TCP协议的工作方式,在这里再稍微深入的说一下TCP协议,为啥只讲稍微深入呢,因为探究深入了以小弟的水平还真说不明白是怎么回事。
大家关于TCP的印象是啥?三次握手四次挥手?还是不丢包?
这里就以一个完整数据传输流程简单的介绍一些TCP是怎样传输数据的,整体流程下图所示。
2.1 TCP连接阶段
第一步就是建立连接。
建立TCP连接
,这里的建立连接并不是真正意义上的建立连接,当设备接入互联网的时候,互联网的设备就已经连接好了,本质上来说互联网所有设备都是相连的,这里的连接而是一个准备数据传输
的过程。
都知道建立连接要三次握手
,
这里引入几个问题,有问题的小伙伴也可以在下面提问,大家来补充答案哦:
1、既然设备接入网络客户端和服务器就已经连接了,为什么TCP通信还要建立连接
?
答:更好的保证可靠性,经过三次握手也可以让通信双方验证各自的发送能力和接收能力是否正常,同时交换一些必要参数。
2、建立连接为什么要三次握手?
答:三次是可靠性和效率兼顾的次数,具体可以看下图。估计有好奇宝宝还会疑问两次握手不行吗?还真不行,如果没有最后一个ACK, 此时主机B 是无法知道自己的发送能力和对方的接收能力是否正常,ACK后面会说。还会问四次握手可以吗?答案当然是可以的,甚至无数次都可以,但是这样就丢失了效率,有点因噎废食。
3、三次握手干了什么?
答:总体来说就是发送了三次TCP报文。
看一下在连接过程中到底传输了什么,这里以ML302模组连接TCP服务器为例,下图为TCP服务器抓包结果:
可以从图中看出,TCP连接的确经历了三次握手。
第一次握手,模组-->服务器,模组15885端口向服务器9090端口发送了一段TCP报文,报文内容即下图蓝色部分数据,具体含义可以参照《网络协议1协议栈》中关于TCP报文头的介绍部分。
其中主要内容有[SYN]、Seq=0、Win=24000、MSS=1360、WS=1这几个参数。
SYN,同步序列号(Synchronize sequence numbers),作用也就是同步信息收发双发,也就是建立连接,把携带SYN标识的称为同步报文段。
Seq=0,序列号(sequence),用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节。表示的是我方(发送方)这边,这个packet的数据部分的第一位应该在整个data stream中所在的位置。当存在SYN时,这个值为初始值,之后的首次数据发送均需要在这个初始值上+1。理论上,它是随机的。
关于这个序列号的变化规则可以看下表。
类型 | 握手(SYN)或终止(FIN) | 传输 | 数据包为0 |
---|---|---|---|
seq(自己发送) | 上次发送 seq+1 | 上次发送seq+数据长度 | 上次发送seq |
Win=24000,窗口(Window),又称滑动窗口(Sliding Window),这里表示模组能够接收最大数据量大小为24000字节,一般和接收缓冲区大小相等。
MSS=1360,最大报文片段长度(Maximum Segment Size),在连接建立的时候,即在发送 SYN 段的时候,同时会将 MSS 发送给对方(MSS 选项只能出现在 SYN 段中!!!),告诉对端它期望接收的 TCP 报文段数据部分最大长度。
WS=1,窗口因子(window scaling),窗口值*窗口因子=最终的窗口值。但是并不是所有的客户端、服务端都支持窗口因子的。两端都支持,窗口因子才会最终被启用。如有一端不支持,则因子不会被使用。窗口因子是在TCP的SYN包协商的,而且只协商一次。也就是滑动窗口是根据实际情况进行变化的,但是因子是固定的。
第二次握手,服务器-->模组,服务器向模组发送了一段TCP报文,报文内容为下图蓝色部分数据。
其中主要内容有[SYN,ACK]、Seq=0、Ack=1、Win=8192、MSS=1460、WS=256这几个参数。
ACK,确认号是否有效字段(Acknowledgment field significant),只有ACK标志为1时确认序号字段(Ack)才有效。一旦一个连接建立起来,这个字段总是被设置,ACK标志也总是被设置为1。
Ack=1,确认序号(Acknowledgment Number),应当是上次已成功收到数据字节序号加1。具体规则看下表
类型 | 握手(SYN)或终止(FIN) | 传输 | 数据包为0 |
---|---|---|---|
ack(接收对方) | 上次接收 seq+1 | 上次接收seq+数据长度 | 上次接收seq |
第三次握手,模组-->服务器,模组向服务器发送TCP报文数据,如下图蓝色部分所示。
其中主要内容有[ACK]、Seq=1、Ack=1、Win=24000这几个参数。
用白话文说这三次握手应该是:
模组向服务器说:我想要传输数据,我们先同步(**SYN**)一下,还有我的初始序列号是0(**Seq=0**),你别一个劲的向我发数据,我能接收的最大数据量是24000字节(**Win=24000**),记住(由发送方计算)别给我撑爆了(接收缓存溢出),我一次最多能接收1360长度的数据,给多了我不要。
服务器向模组说:我已经收到了你的说的话了,我这边准备好了(ACK),你也记一下(SYN)我的情况,balabalabala。
模组向服务器说:好的,我这边也准备好了(ACK),我们可以开始传数据了。
2.2 TCP通信阶段
连接好了,就可以开始发送数据了,下图是模组向服务端发送4014字节数据的抓包情况。
可以从图中看到,4014字节模组总共发送了三次,服务器回了两次。
还是从疑问出发,同样有问题的小伙伴也可以在下面提问:
1、为什么4014字节要分开发送?
答:这里就是TCP特性之一==数据分段==,TCP分段产生原因是MSS。可以从图中看到第一段和第二段发送的数据长度为1360,这个值刚好是连接时发送的MSS=1360。
2、为什么MSS这个值是?
答:协议栈会根据一个 叫作MTU的参数来进行判断。MTU 表示一个网络包的最大长度,在以太网中一般是 1500 字节。MTU 是包含头部的总长度,因此需要从 MTU 减去头部的长度,然后得到的长度就是一个网络包中所能容纳的最大 数据长度,这一长度叫作 MSS。
3、为什么不一个字节一个字节发送?
答:这个问题比较傻,想也知道如果是一个字节一个字节发送的话,报文头都比数据量更大,这数据传输效率有多低就不想了吧。
4、为什么模组发了两次数据,服务器才应答,不应该是一应一答吗?
答:这里显示了TCP的两个特性,==滑动窗口==、==延迟应答==和==捎带应答==。
ACK 计算是需要时间的,而且网络也会存在堵塞时延,如果每包数据发送方都要等到接收方确认才继续发下一包,那等待确认这一段时间发送方什么都干不了,这样效率太低了,所以这里就引入了==滑动窗口==这一特性,之前已经说过了,类似于接收缓存区,服务器告诉模组我的接收滑动窗口大小为8192*256=2097152字节,所以模组可以不等确认信息返回直接向服务器不断的发数据,可以看下图。
在TCP中,确认应答机制以保证数据的可靠传输。但是是不是接收方接收到数据就立即返回ACK应答呢?但是接收的数据都是先到接收缓存区,然后再由应用程序读取到应用中,如果是接收到数据就立即返回ACK,这时候的缓存区中接收区的数据还没能够由应用程序读取,缓存区的剩余大小就是窗口大小。
但是如果我们延迟一会,等待缓存区中数据被读取,那么剩余的缓存区就会大些——这就是==延时应答==,每个操作系统中设置的等待时间是不一样的。,但是肯定不可能是只延时这么死板,延时应答有数量限制和时间限制两部分:
条件 | 协议规定 | 个人补充(这里为个人猜测) |
---|---|---|
数量限制 | 每隔两个包就应答一次 | 应该是每隔大于等于2个包,可以想象随着网速越快,比如现在家用的100M宽带,每秒可传输12800KB数据,1毫秒就可以传送近13K的数据,前面的MSS介绍了每包数据最大约为1.5K,也就是1毫秒就能传送近10包数据。 |
时间限制 | 超过最大延时时间就应答一次,一般是200ms | 但是这个值是可以设定的,随着网速提升这个值肯定会越来越小的,理由同上。 |
发现没有,上面抓包图中,模组发了两包数据,服务端只回应了一个ACK应答信息,观察应答信息,其中将模组的发的两包数据的应答合并了(Ack=2721),模组发了两次1360字节长度的数据,服务端直接回复“我已经收到了前2720字节数据”。
==捎带应答==
上面介绍了滑动窗口这一机制,所以就多出来了一个步骤,接收方得告诉发送方我的窗口大小的变化,理论上应该是应用程序把数据从接收缓存区取出的时候向发送方发信息告诉我的窗口大小目前是多少。
前面我们知道接收方发送应答消息是需要时间的,要是这个时间和应用程序读取缓存区的时间刚好一致呢,分别发送一个应答消息,一个窗口更新消息是不是太傻了,从上面的抓包图也可以看到,应答消息和窗口更新是一起发送的,因为它们是TCP头部中不同的区域,互不影响。
从这个扩展一点呢,如果双方都在同时发送数据呢,是不是可以在数据包的头部包含应答消息和窗口更新,当然是可以的,这里就引入了==捎带应答==,即在发送数据的时候捎带着其他信息。
其实TCP传输中还有很多特性,但是一个一个将就内容太多了,还不如看书呢。剩下的就留给小伙伴们补充。
- 确认应答机制
- 超时重传机制
- 滑动窗口机制
- 快速重传机制
- 流量控制机制
- 拥塞控制机制
- 延时应答机制
- 捎带应答机制
2.3 TCP断开阶段
前面说了连接阶段,再说这个阶段觉得索然无味了,总了个之呢,就是交互了四次控制信息,发送了四次报文,是不是呢,我们还是看一下抓包情况。
有点奇怪,发送的是RST,而且只有一条,表格贴在下面了,懒得翻回上一篇看了,可以看到设个RST表示强制断开连接,应该是302的设置就是这样吧。
看一个正式的,下面以本机电脑连接服务端的情况,可以看到,的确是4次挥手,具体的小伙伴来细说。
评论 (0)