17-TCP 协议(迟到的 ACK —— Windows )

1. 引言

我们知道,TCP 协议中,需要对接收到 TCP 段进行确认。有两种方式可以减少 TCP 报文段. 一种是累积确认,另一种是捎带确认。

  • 累积确认

有时候,发送方发送速度非常快,接收方一下下接收到了好几个 tcp 段,可以通过累积确认的方式,一次确认好几个 tcp 段,这样减少报文段的传输。

  • 捎带确认

有时候,双方互相发送数据,当接收到对方的 tcp 段后,先不着急确认,而是等待一会儿,连同数据和 ack 一起发送过去,这种情况叫捎带确认。如果等了一会儿(到时间了),接收方还没有数据要发送,那就直接回复一个纯 ack 过去,这样的 ack 称为延时的 ackDelayed ACK).

本文就来看一下,操作系统是如何进行时延确认的。

2. 实验

本节实验,我们使用新的客户端 echo_client.cpp 和 新的服务器 echo_serv.c.

  • 客户端:unp/protocol/tools/winclient/echo_client.cpp,部署在 Windows 上。
  • 服务器:unp/protocol/tools/tcpserver/echo_serv.cpp,部署在 Linux 上。

echo_serv 的功能是将接收到数据发送回去。echo_client 的功能是从键盘接收字符,每接收到一个字节就立即发送出去。

当 echo_client 连接到 echo_serv 的时候,在键盘上键入字符,echo_client 会将键入的字符一个一个的发送到服务器,然后服务器将收到的字符回送回来。echo_client 接收到回送的字符后,将其打印到屏幕。

特别注意的是,echo_client 启动后,从键盘键入字符,是不会显示在屏幕上的。这个功能是由函数 getch 完成的,如果不太明白,建议先 baidu or google 一下这个函数。

2.1 实验步骤

  • Linux 端启动 echo_serv
$ echo_serv 192.168.80.130 8000
  • Windows 端打开 OmniPeek 进行抓包,然后启动 echo_client
$ echo_client 192.168.80.130 8000

然后分别键入 loveq 这五个字符,一定记得,是五个字符,最后一个字符 q 不要丢了!!!


这里写图片描述
图1 键入 loveq

可以看到显示了 love,因为这四个字符是服务器发送回来的。而键入的 q 直接导致了客户端退出。

2.2 抓包结果


这里写图片描述
图2 抓到的数据包

先来分析一下,4 号数据包,客户端给服务器发送了字符 l,服务器直接回送了 5 号数据包 ack. 详细情况见图 3.


这里写图片描述
图3 延时的 ACK

然后,服务器紧接着又将收到的数据发给了客户端(6号包)。

7 号包对服务器发来的 6 号包进行确认.

此后,我们看到所有客户端对服务器回显的数据进行确认,都是只有 ack 而没有携带数据,因为你在输入l、o、v、e 的时候很慢很慢的,客户端等不及你输入数据就先把 ack 发过去了。

客户端有没有等你的数据呢?实际上是有的,看图 2 中红框,这个 Delta Time 表示相对上一个数据包的时间,我们可以发现这个时间基本上都是 200 ms 左右。

也就是说,如果 tcp 在等待了约 200ms 左右,还是没有数据要发送,就把这个 ack 单独发送出去了。

以上是 windows 表现的结果,在 Linux 中又是另一番景象,下回分解。

3. 总结

  • 什么是时延 ACK
  • Windows 是如何实现的