linux网络 | TCP报头之六个标记位与部分可靠性策略
前言:本节内容讲述TCP报头里面的六个标记位以及一些保证TCP可靠性的方案(连接管理设计状态的分析和滑动窗口占用篇幅大,放在下一节讲解)。 TCP可靠性方案也是学习TCP的一个重要的板块。 本节就来讲述一些可靠性方案。 下面废话不多说,开始我们的学习吧!
ps:本节内容需要一些前面学习的穿插内容, 友友们最好看一下这篇文章再来学习比较好哦:linux网络 | 传输层TCP | 认识tcp报头字段与分离-CSDN博客
目录
为什么要有六个标记位
六个标记位解析
ACK、SYN、FIN
PSH
RST
URG
可靠性策略
检验和
序列号
确认应答
超时重传
为什么要有六个标记位
服务器和客户端 1: n进行tcp通信的时候,一定要先建立连接,三次握手。然后结束通信,tcp也要断开连接四次挥手。在建立和断开之间,还要进行正常的数据通信,tcp在建立连接的时候一定要发送tcp的报文。 断开连接也要, 正常通信也好,都要发送tcp报文(至少要有报头, 可以没有数据)。所以,通信之前,有些tcp请求是用来建立链接的,有些是用来正常通信的,有些是用来断开连接的。 这就注定了tcp收到的报文, 本身是有类型的。
这个类型,接收方怎么知道报头的类型是什么呢? 所以就有了六个标记位 (区分tcp报文的类型)。
六个标记位解析
ACK、SYN、FIN
关于ACK,SYN,FIN很简单。 这三个是在三次握手和四次挥手的时候要使用的标记位。 具体就是:
- ACK确认号是否有效,即确认应答
- SYN请求建立链接;我们把携带SYN标识的称为同步报文段,即请求握手。
- FIN: 通知对方,本端要关闭了
PSH
PSH是提示接收端应用程序立刻从TCP缓冲区把数据读走
什么意思, 就是说如果我们的发送方向对方发送数据,发送了大量的数据,导致对方的接收缓冲区已经满了。这个时候,会发生什么呢?
是不是就是不能再像对方的接收缓冲区发送数据,然后发送方就堵塞了!!! 但是,发送方堵塞不能一直堵塞,所以如果接受方的上层一直不处理接收缓冲区的报文,那么发送方就可以发送一个PSH报文。表示催促对方赶紧处理报文腾出位置! 即表示提示对方应该立刻把TCP缓冲区里面的报文读走。
RST
RST对方要求重新建立连接,我们把携带RST标识的称为复位报文段
我们说TCP是保证可靠性的。那么是否建立连接,必须得成功呢?——tcp虽然保证可靠性,但是tcp允许链接建立失败。
我们要知道的另一个点是,一个客户端在服务端求接,这个时侯我们的服务定同时存在多个已经建立好的链接,这么务摊接,服务要对这么多接进行管理,关闭,所以服务端就要对这些链接进行管理。
所以,我们如何理解”链接”概念呢?
客户端和服务器双方建立好连接的本质,就是双方的操作系统内为链接创建struct结构体。这个链接结构体里面包含链接相关的属性,比如说链接什么时候建立、客户端的端口号等等。
我们也可以把链接结构体之间用指针相连,然后我们对连接的管理,就转化成了对链表的增删查改。
CS维护链接也是有成本的。这里的这个成本就是上面创建结构体,要花时间,要花空间。
在我们大量客户端进行连接时,就可能出现链接出现异常的情况。就比如客户端认为链接建立好了,但是服务器认为链接没有建立好, 这个时候客户端创建了结构体, 服务端没有创建, 这个成本就花在了客户端这边。 (后面我们会谈一下这个成本问题)
我们上面说CS是有成本的, 首先我们先不谈成本的解决方法, 先看一下为什么会有成本,我们用三次握手来细讲:
这些请求的线之所以不直直的画,就是因为从请求发送到拿到请求之间是有时间差的。
上面的三次握手中有一个小问题,就是在客户端最后一次ACK的时候,是在客户端发出ACK后就认为建立连接成功了呢,还是要知道服务器已经收到ACK后客户端才会认为连接已经建立好呢?
这里的答案是,只要发出去,就认为连接成功,没有应答!!!!
所以tcp三次握手, 本质上是在赌, 赌最后的ACK服务端能够收到。但是前两次握手的可靠性是能够保证的,不能保证的只有最后一个ACK。
- 所以,client在三次握手中,认为只要把三次握手中的第三次报文发出,就认为连接建立好了!!!
- 如果ACK丢失了,此时服务端就认为这个连接没有建立好,此时就是客户端和服务端对连接是否建立成功认知不一致。然后客户端这个时候发消息,此时服务端认为连接还没有建立好,就会应答RST标记回去,重新建立连接。重新三次握手。
综上, RST是客户端和服务器,双方对连接认知不一致,即连接建立异常的情况下重新连接使用的。
URG
URG是紧急指针是否有效
- 有些情况下,想要让上层高优先级去处理一些数据,此就可以设置一个URG标志位,此URG标记位如果为0,表示无效,16位紧急指针没有意义,填写一个0即可。
- 但是URG如果为1,表示这个报文内部包含了紧急数据,要求当前要紧急处理,这个16位紧急数据就代表在整个tcp数据当中,紧急数据的偏移量是多少。紧急数据只允许是一个字节。
什么情况下我们会使用这个紧急数据呢?
假如这个服务端很卡,所以客户端就要询问他为什么这么卡。这个时候客户端就要向服务端发起询问,询问服务器是怎么回事, 所以我们就需要服务端支持读取紧急数据 + 软件功能提供状态编号
假如服务端这个时候很卡,我们发送了多少数据都没有回应。这个时候我们就可以发一个紧急数据,这个紧急数据,在服务端内有专门的位置读取这个紧急数据。然后服务端读取这个紧急数据,读上来之后,因为处理的信息量不大,然后服务端就要把状态返回给客户端(比如1,2,3)这样询问和响应的数据就加快了。
可靠性策略
检验和
十六位检验和, 报头中的字段,和UDP的一样, 都是检验数据在传输过程中有没有出现偏差。
序列号
32位序号, 避免了数据包乱序的问题和数据包的重复问题(每一个序号只有一条报文)
确认应答
保证了确认应答消息之前的消息的可靠性。 值得一提的是, 确认应答, 起始就是ACK,所以就是ACK应答机制。
超时重传
上一节的超时重传我们有一些细节没有讲到, 这一节我们补充一些:
为什么要有超时重传,主机A在向主机B发送数据时,如果是数据本身丢失了。即主机B根本就不知道A给他发过数据。所以B也就不会给A进行应答。那么A就收不到B的应答,他就不知道自己刚刚的报文到底有没有被B收到。
所以为了给丢了做一个定义,就规定了一个特定的时间间隔,凡是超过这个时间间隔的报文,如果没有收到应答,那么就当成丢了。超时之后,当成丢了之后,就要开始重新发送报文, 这个就叫做超时重传机制。
另外还有一种情况就是主机A给主机B发送消息。主机B收到了消息,发送回去确认应答,但是确认应答丢了,主机A同样收不到应答,超过特定时间间隔后,主机A就要进行超时重传。
对于第一种情况,主机A确认丢失后重发就重发了。但是第二种情况下,主机B明明收到了主机A的报主机A还要重新发,就势必会造成主机B收到 重复报文重复报文也是一种不可靠情况,所以就要去重。所以这里又用到了序号。
序号是如何设置的呢?
设定特定时间间隔怎么设置呢。这个我们就要思考一个问题。
就是如果此时网络速度很快,那么这个时间间隔就不能太长。因为如果时间太长,在网络速度很快的情况下就非常浪费时间。
如果此时网络速度很慢,那么这个时间间隔就不能太短,因为如果时间太短,在网络速度很慢的情况下,就很容易发送一个报文,这个报文就发生超时,然后重传。这样就容易发送大面积重传的现象。
所以,我们就可以得到一个结论,超时重传的时间一定是动态的,是随着网络情况发生变化的。
操作系统中的解决方案是:Linux中(BSD Unix和Windows也是如此),超时以500ms为一
个单位进行控制,每次判定超时重发的超时,时间都是500ms的整数倍 。
如果重发一次之后,仍然得不到应答,等待 2*500ms 后再进行重传。如果仍然得不到应答等待 4*500ms 进行重传依次类推, 以指数形式递增,累计到一定的重传次数,TCP认为网络或者对端主机出现异常,强制关闭连接。
——————以上就是本节全部内容哦, 如果对友友们有帮助的话可以关注博主, 方便学习更多知识哦!!!