1. 引言
我们知道,TCP 协议中,需要对接收到 TCP 段进行确认。有两种方式可以减少 TCP 报文段. 一种是累积确认,另一种是捎带确认。
- 累积确认
有时候,发送方发送速度非常快,接收方一下下接收到了好几个 tcp 段,可以通过累积确认的方式,一次确认好几个 tcp 段,这样减少报文段的传输。
- 捎带确认
有时候,双方互相发送数据,当接收到对方的 tcp 段后,先不着急确认,而是等待一会儿,连同数据和 ack 一起发送过去,这种情况叫捎带确认。如果等了一会儿(到时间了),接收方还没有数据要发送,那就直接回复一个纯 ack 过去,这样的 ack 称为延时的 ack(Delayed 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 是如何实现的