【网络】TCP报头&&可靠性

TCP全称是“传输控制协议(Transmission Control Protocol)”,是当今运用最多的传输层协议。TCP能被广泛使用,主要原因在于它保证了可靠性,并且为了传输效率也做到努力。本文会先介绍TCP报头的字段,并且渗透TCP保证可靠性的措施。

TCP报文的格式

先来见一见TCP报文

TCP报文的格式明显比UDP复杂,多了很多字段。也就注定了TCP的学习难度会远大于UDP。

所以,博主将逐个讲解报文的字段。并且介绍TCP保证可靠性的原因。


对于这个报文格式。

  • 首先要解决的是有效载荷和报头如何分离。
  • 其次、数据如何向上交付。

有效载荷和报头的分离问题?

udp是固定首部长度。而tcp首部长度是不固定的,因为包含了选项字段。

tcp的分离规则:先读取前20字节,获取首都长度。也就是4为首部长度。4位首部长度的单位是4字节表示的范围是[0,60],因为首部长度最少是20字节,所以修正一下范围为[20,60]

获取到首部长度后,就能做到有效载荷和报头的分离。

向上交付的问题?

数据的向上交付是依据目的端口。


应用层拷贝数据到传输层,会发生什么?怎么从传输层将数据交付?

传输层会存在大量的tcp数据报。所以要对这些报文进行管理。管理的方式就是sk_buffer是一个链表的形式。

报头的实质就是一个位段结构体,里面包含了每个字段的数据。

应用层将数据拷贝到传输层时,传输层会为数据申请一块专有的缓冲区,并且用sk_buffer结构体的data指针指向数据其实,tail指针指向数据结尾,最后将tcphdr报头拷贝到data指针之前,然后将data指针指到最前面。最后链接入链表。

往上层交付数据的时候,不再拷贝数据,而是改变head指针,移到有效载荷的起始位置。


流量控制

TCP为了报文可靠性,每次发送的消息,只有收到对方的回应后,才算真正发出去了。

在TCP传输层中存在发送缓冲区和接收缓冲区。如果对端是服务器,必然同时存在大量的报文在缓冲区中。而应用层来不及将接收缓冲区的数据读取,就会导致缓冲区的数据越来越多,剩余的空间越少。那么一旦缓冲区满了,如果再有数据到来,是不是只能丢弃?

但是数据跨越网络好不容易到达的对端,就被丢弃,显然是不合理的。因此在TCP层就会存在一个标志自己接收缓冲区大小的字段,也就是16位窗口。

所以——流量控制就是保证TCP可靠性的第一谈。

用法:

由于对端收到消息后,就会发送ACK报文(就是应答报文,裸的报头,将ack标记位设为1)

应答客户端的同时,服务器想通知自己的接受缓冲区大小,就会将16位窗口大小设置。然后在应答报文中携带窗口大小。

极端情况:对端接受缓冲区满了,数据会被放到发送缓冲区中。如果发送缓冲区也满了,那么上层就必须阻塞等待。


确认应答机制和发送数据的模式

TCP通信的双方地位是对等的,为了保证可靠的将数据发出,对端在接受到报文时,必须发送一个确认报文。

举一个简单的例子:电视剧特种兵作战时候,如果张三发现敌人,常常就会说:李四李四,A点发现敌人,收到请回答。这时候张三将自己的消息发送出去了,但是在没有收到李四的回答之前,它是不确定自己的消息真正的发出的,甚至过了一段时间没人回答就要重发。只有李四对张三的消息回复了,张三才能确定可靠的发送出去。

发送模式

但是这种发送模式的效率实在是太低了,同一时间端只能发送一份报文。如果是网络传输是几MB,而一份报文只有几K,那么发送的效率实在太低了。为了提高效率,一种发送时间可以重叠的机制被引入。

 

32位序号

数据被发出后,先发出的数据不一定先到达,主要是网络的波动和阻塞。也就是说,报文到达对端可能是无序的。而TCP是面向字节流的,上层只会一直收取数据,所以必须保证报文按照顺序组织。 因此引入32位序号。

保证报文按序到达——TCP保证可靠性的第二谈

所以通过32位序号就能给到达的报文排序,序号在前的报文自然就被排到前面。然后组织好顺序在往上交付,就是实现了按序到达。

32确认序号

服务器收到客户端的报文之后,并且能够根据报文的序号进行排序,保证序号的按序到达。那么下一步服务器就要对客户端进行ack。ack也必须保证到达客户端有顺序,所以再引入确认序号。

确认序号:序号+1,并且规定:确认序号之前的所有报文被对方全部收到了。

比如是确认序号是100,那么确认序号就是100+1,101。

为什么要规定确认序号之前的报文全被接受了?

允许少量的报文丢失。

如果101 201 301ack丢失了,但是401却收到了。客户端就能知道100 200 300 400的报文已经到达对方了,就不需要重新发送报文,是提高效率的做法。

 有一个问题:为什么需要确认序号和序号呢?不能压缩成一个吗?

因为tcp是全双工,客户端给服务器发报文,同时服务器也会给客户端发报文。双发地位是对等的。为了提高效率,一种捎带应答的方式被使用。

如果需要发数据,同时又要ack。就会被合并到一份报文中,提高效率。

发报文需要序号标志位,ack也要标志位。所以不能省略。


讲完了窗口大小和确认序号,接下来来介绍一下标记位。

一台服务器同时会遇到许多的不同的连接,有建立连接的、断开连接的、异常处理的。为了区分这些不同类型的连接,对于每一份连接都应该有标记。

六位标记位

这些标记位分别是SYN、FIN、ACK、URG、PSH、RST

SYN和FIN是建立连接和关闭连接时候用到的标志位。ACK是应答标记。URG是紧急标记位。PSH是催促上层尽快取走数据。RST是重置连接。下面将介绍这些标记位的使用,及其场景。

URG:紧急标记位

如果URG被设置,通常会设置紧急指针。紧急指针是有效载荷中紧急事件位置的偏移量。

一个紧急指针只能标记一个字节

数据是按照顺序排队写入的,如果有异常事件触发,那么会需要设置紧急标记位。告知对端的上层先处理紧急消息,其它消息滞后处理。

在sento中的flage字段就有一个MSG_OOB表示带外字段,设置紧急事件。

场景:

  1. 需要暂停/终止服务器时,但是服务器正在排队处理之前的消息。这时候紧急指针的事件就会被优先处理。
  2. 询问服务器状况,如果服务器当前处理速度较慢,就可以发送带紧急指针的报文。服务器收到报文后优先回答对方我的状态。

PSH:推送

PSH被设置就是告知上层尽快把数据向上交付。

重新审视一下流量控制。

如果客户端得知对端的接受缓冲区变为0时,就会进入阻塞状态。

那么什么时候结束阻塞状态,总不能一直阻塞下去?

1.客户端定时给服务器发送报文,会得到ack并且获取服务器的窗口。这时候通常会带上PSH标记位,告诉服务器上层尽快处理缓冲区内容。

 2.服务器的接受缓冲区由0变为非0时,会主动发送报文,告知缓冲区大小。

这俩种方式共同使用,都能让服务器知道什么时候停止阻塞。

场景:

像实时数据传输之类的,如直播、游戏等,报文通常都会携带PSH


RST:重置标记位

引入一个问题,三次握手必须成功吗?

答案是错的,三次握手不一定都会成功。就拿客户端主动向服务器发起三次握手为例子。

客户端的接受到服务器的ACK后,客户端就默认三次握手成功。而对于服务器而言,必须等到最后一份ACK收到之后,才认为建立连接完成。所以客户端和服务器认为的建立连接完成的时机是不一致的。

所以前俩次报文丢失是没关系的,因为对方都能可靠的知道,重新发送报文。

而最后一次ACK的丢失是无法预知的。

这就导致了一个问题:客户端认为已经建立连接,而服务器任务连接没建立完成。

如果客户端给服务器发了一条消息,而服务器尚在未连接状态,就会给客户端发送一个报文,将RST标记位设置,告知客户端重新建立连接。

 

 场景:常用于链接建立认知不一致,重新建立请求!


 简单谈完了标记位,下面来介绍一下TCP保证可靠性的第三谈——超时重传

超时重传

如果TCP请求被发出后,没有收到ack。有俩种情况

1.请求报文丢失

2.ack丢失。

如果是请求报文丢失,那么重新发送一份报文即可。

而ack丢失,那也要重新发送一份报文。而接受方会接受到同一份报文,就必须对报文去重,这里隐含着一个知识:TCP会短暂保存接受到的报文。

所以超时重传的重传机制很简单。

那什么时候重传呢?既不能太快也不能太慢。

规定以500MS为起始,如果还是没收到报文第二次2*500MS的时间发送报文。

第三次以4*500MS的间隔发送

超时的规则就是2^n *500MS

至此TCP报文部分就介绍完毕,并且渗透了TCP可靠性的原因。下文将继续介绍TCP保证可靠性、提高效率的策略 

  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深度搜索

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值