【计算机网络】TCP协议

TCP协议的复杂我们在上层接口已经展现出来了,报文也是相对复杂的

TCP协议

TCP 全称为 "传输控制协议(Transmission Control Protocol"). 人如其名, 要对数据的传输进行一个详细的控制;

TCP 协议段格式

对于上图中的数据不必多说,就是应用层拷贝进去的数据。

我们先进行一下简单的介绍,再解释一下我们现在能理解的位段。

  • 源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去;
  • 32 位序号/32 位确认号: 后面详细讲;
  • 4 位 TCP 报头长度: 表示该 TCP 头部有多少个 32 位 bit(有多少个 4 字节); 所以TCP 头部最大长度是 15 * 4 = 60
  • 6 位标志位:
    ○ URG: 紧急指针是否有效
    ○ ACK: 确认号是否有效
    ○ PSH: 提示接收端应用程序立刻从 TCP 缓冲区把数据读走
    ○ RST: 对方要求重新建立连接; 我们把携带 RST 标识的称为复位报文段
    ○ SYN: 请求建立连接; 我们把携带 SYN 标识的称为同步报文段
    ○ FIN: 通知对方, 本端要关闭了, 我们称携带 FIN 标识的为结束报文段
  • 16 位窗口大小: 后面再说
  • 16 位校验和: 发送端填充, CRC 校验. 接收端校验不通过, 则认为数据有问题. 此
    处的检验和不光包含 TCP 首部, 也包含 TCP 数据部分.
  • 16 位紧急指针: 标识哪部分数据是紧急数据;
  • 40 字节头部选项: 暂时忽略;

我们学习每个协议时都需要面对两个问题

  1. 如何解包?
  2. 如何分用?

对于解包:

我们看到报文中有4位首部长度,同时报头部分为20字节。

4位首部长度的单位是4字节->[0, 15]->[0, 60],也就是说报头部分最多有60字节,剩下的40字节是选项的大小。

如果我们的报文不带选项,首部长度应该是多少呢?

答案就是0101

对于分用:我们有16位目的端口号,故可以直接找到对应的进程。

确认应答(ACK)机制

ACK就是acknowledgement(应答)。

我们先来看具体的一个例子

当A和B距离的很近时,他们之间的交谈很容易

但当距离的很远时,那么通信就不是那么容易了

因为距离的很远,所以当你问问题时不知道对方是否收到,就像A问B吃饭了吗,除非B给你回复,否则你是不清楚B是否收到的。

但只要B给你回复,那么就说明上一句一定被B收到了。

这也就说明最新的一个回复是永远无法确定是否被收到。

此时我们就可以对现实的这个例子下一个结论:

只要收到了应答,就能保证我发的数据一定被对方收到了

我们映射到网络中

我们所谓的ACK就是当其中一端发了一个消息,另一端发一个ACK进行回复,若是没有收到ACK就是代表没有收到消息!

且不用对ACK进行ACK,如果这样那就不成了先鸡还是先蛋的问题?

通信模式

我们常见的通信模式有两种

左侧的效率高,右侧的效率低

所以更常见的是左侧。

但是如果发的这么密集,如果ACK丢了一个会怎么样?

就无法知道那个是缺失的了。

所以我们需要一个唯一标识符。

更细致一点的图

也就是序号。

确认序号原则上就是收到的序号+1,其中若是收到了3001,那么就说明3001之前的报文全部都收到了。

这个定义与滑动窗口有关,我们暂时不关心。

此时我们暂时先稍微看两个特殊情况,具体的会在后边谈。

  1. 当1001ACK收到,2001,3001...没收到,我们不会立即重传,会超时重传或者快重传之类的。
  2. 当4001收到,1001,2001,3001未收到会影响吗?定义规定了4001收到就代表4001之前的都收到了所以不影响,所以我们也支持少量的弄丢。

问题

问题一: 那么为什么设置为两个序号?

发的时候用一个,ACK的时候也用一个,事实上设置一个序号的话完全可以,但是我们有一个机制叫做捎带应答:

意思就是服务器进行ACK时也正好将自己要发送的数据一起发送了,这就是捎带应答。

可以大大的提高效率,所以需要两个序号。

问题二: 客户端如何知道收到的报文是应答还是携带数据?

同样,请求也有各种各样:请求链接,请求断开...

所以我们需要一个类型进行表示

我们的ACK就在其中,属于其中一种。

捎带的话也不冲突,携带上数据即可。

问题三: 如何理解序号?

逻辑上我们将发送缓冲区当做一个字符数组

所以我们所谓的序号其实就是数组下标,发送1000,其实就意味着将1-1000数组内数据全部发送,发送2000就代表将1001到2000发送,1000的ACK就是1001,2000的ACK就是2001...以此类推。

超时重传机制

• 主机 A 发送数据给 B 之后, 可能因为网络拥堵等原因, 数据无法到达主机B;

• 如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会进行重发;

但是, 主机 A 未收到 B 发来的确认应答, 也可能是因为 ACK 丢失了;

因此主机 B 会收到很多重复数据. 那么 TCP 协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉.

这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果.

那么, 如果超时的时间如何确定?

• 最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回".

• 但是这个时间的长短, 随着网络环境的不同, 是有差异的.

• 如果超时时间设的太长, 会影响整体的重传效率;

• 如果超时时间设的太短, 有可能会频繁发送重复的包;

TCP 为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间.

• Linux 中(BSD Unix 和 Windows 也是如此), 超时以 500ms 为一个单位进行控制, 每次判定超时重发的超时时间都是 500ms 的整数倍.

• 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.

• 如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.

• 累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接.

注意:网络是十分复杂的,先发的不一定先到,但是到达接收缓冲区是肯定按照顺序的,否则接收方read时岂不是错乱了,所以需要序号进行按序到达。

至此我们的序号已经有三个作用了:

  1. 用来ACK(报头)
  2. 报文去重
  3. 按序到达

连接管理机制

在正常情况下, TCP 要经过三次握手建立连接, 四次挥手断开连接

我们先看三次握手

其中我们又会学到新的标记位:SYN(Synchronization),这个就是建立连接时报头需要携带的标记位。

我们connect发起了三次挥手,剩下的都是由OS自主完成的。

注意:accept不参与三次挥手

我们感性的理解一下:

第一次握手:做我女朋友吧

第二次握手:好啊,什么时候开始?

第三次握手:现在!

虽然最新一条客户端无法保证服务器能收到,但是一旦发出我们就认为三次握手成功了!

所以本质就是在赌!堵可以建立成功,即最后一个ACK被对方收到了。

看似很牵强,但实际上至少已经能相互验证可以互相发消息没问题的了。

就是因为在堵,所以有特殊情况的出现,也就是最后一个ACK服务器未收到,虽然说会超时重发,但此时客户端认为已经连接完成了。

客户已经发送消息了,问题就出现了,明明连接还没完全建立却发送了消息,此时服务端应答时需要一个新的标志位RST(reset)重置。

对异常连接进行释放。

所以至此以后,可能由于各种各样复杂的网络情况导致异常链接都重置即可!

持续更新~

相关推荐
suifen_38 分钟前
RK3229_Android9.0_Box 4G模块EC200A调试
网络
铁松溜达py44 分钟前
编译器/工具链环境:GCC vs LLVM/Clang,MSVCRT vs UCRT
开发语言·网络
衍生星球5 小时前
【网络安全】对称密码体制
网络·安全·网络安全·密码学·对称密码
掘根5 小时前
【网络】高级IO——poll版本TCP服务器
网络·数据库·sql·网络协议·tcp/ip·mysql·网络安全
友友马6 小时前
『 Linux 』HTTP(一)
linux·运维·服务器·网络·c++·tcp/ip·http
2401_872514976 小时前
深入探究HTTP网络协议栈:互联网通信的基石
网络·网络协议·http
Static_Xiao7 小时前
计算机网络 8.*结构化布线
计算机网络
chenjingming6667 小时前
windows使用tcpdump.exe工具进行抓包教程
网络·测试工具·tcpdump
初黑子zzz7 小时前
rsync
网络