我也被建议在这里问,因为有关协议的具体问题是主题,但如果有人感兴趣,这个问题也对ServerFault有一点悬念。
我正在阅读有关 TCP 数据流、延迟 ACK和Nagle's Algorithm 的信息。
到目前为止,我明白:
- TCP 上的延迟 ACK实现会在接收到的段的确认上产生延迟,以使应用程序有机会在确认的同时写入一些数据,从而避免发送空 ACK 数据包并导致网络拥塞。
- Nagle 的算法实现声明您不能发送一个小的 TCP 段,而另一个小段仍然未被确认。这避免了流量被加载了几个tinygram。
在某些交互式应用程序上,例如 Rlogin,Nagle 的算法和延迟 ACK可能会“冲突”:
当我们键入键盘输入时,Rlogin 会将键盘输入发送到服务器,并且某些键(如F1)会生成一个以上的字节(F1 = Escape + 左括号 + M)。如果这些字节被一一传送到 TCP,它们可以在不同的段中发送。
服务器在获得整个序列之前不会回复回显,因此所有 ACK 都会被延迟(期望来自应用程序的一些数据)。另一方面,客户端会在发送下一个字节之前等待第一个字节确认(尊重Nagle 算法)。这种组合最终导致“滞后”的 Rlogin。
tcpdump
在 Rlogin 上发送的F1和F2键如下所示:
type Fl key
1 0.0 slip.1023 > vangogh. login: P 1:2(1) ack 2
2 0.250520 (0.2505) vangogh.login > slip.1023: P 2:4(2) ack 2
3 0.251709 (0.0012) slip.1023 > vangogh.login: P 2:4(2) ack 4
4 0.490344 (0.2386) vangogh.login > slip.1023: P 4:6(2) ack 4
5 0.588694 (0.0984) slip.1023 > vangogh.login: . ack 6
type F2 key
6 2.836830 (2.2481) slip.1023 > vangogh.login: P 4:5(1) ack 6
7 3.132388 (0.2956) vangogh.login > slip.1023: P 6:8(2) ack 5
8 3.133573 (0.0012) slip.1023 > vangogh.login: P 5:7(2) ack 8
9 3.370346 (0.2368) vangogh.login > slip.1023: P 8:10(2) ack 7
10 3.388692 (0.0183) slip.1023 > vangogh.login: . ack 10
现在的疑问:即使我阅读的页面指出服务器在获得整个密钥序列之前没有回复回显,但通过捕获的数据包tcpdump
显示密钥正在各自的 ACK 上回显(第一个回复是 2字节长,因为ESC的回显是两个字符 - 插入符号 + 左括号)。
如果数据正在从应用程序发送到 TCP(回显响应),为什么 ACK 会延迟?根据所陈述的,关于服务器在回显之前等待完整序列,ACK 不应该不包含直到最后一个 ACK 的回显,这将包含整个序列回显?
编辑:
这是tcpdump
修改后的 Rlogin 的输出,没有 Nagle 算法(TCP_NODELAY 标志):
type Fl key
1 0.0 slip.1023 > vangogh.login: P 1:2(1) ack 2
2 0.002163 (0.0022) slip.1023 > vangogh.login: P 2:3(1) ack 2
3 0.004218 (0.0021) slip.1023 > vangogh.login: P 3:4(1) ack 2
4 0.280621 (0.2764) vangogh.login > slip.1023: P 5:6(1) ack 4
5 0.281738 (0.0011) slip.1023 > vangogh.login: . ack 2
6 2.477561 (2.1958) vangogh.login > slip.1023: P 2:6(4) ack 4
7 2.478735 (0.0012) slip.1023 > vangogh.login: . ack 6
type F2 key
8 3.217023 (0.7383) slip.1023 > vangogh.login: P 4:5(1) ack 6
9 3.219165 (0.0021) slip.1023 > vangogh.login: P 5:6(1) ack 6
10 3.221688 (0.0025) slip.1023 > vangogh.login: P 6:7(1) ack 6
11 3.460626 (0.2389) vangogh.login > slip.1023: P 6:8(2) ack 5
12 3.489414 (0.0288) vangogh.login > slip.1023: P 8:10(2) ack 1
13 3.640356 (0.1509) slip.1023 > vangogh.login: . ack 10
可以注意到在第 4 段,延迟约为 0.2 毫秒,即使 Nagle 的算法已关闭(因此所有特殊密钥字节一起到达并且可以一起处理)。在第 6 段,我们无法识别约 0.2 毫秒的延迟,因为服务器需要一段时间来重新处理和重新打包一些丢失段的重传,但这个延迟超过 2 秒。
在F2键示例中,在第 11 段,我们还可以注意到约 0.2 毫秒的延迟。我们无法在第 12 段识别它,因为它可能是在第 11 段之后发送的。
这确实表明@MattTimmersans 的答案是正确的,这可能是这本书对段延迟的误解。它们确实可能是网络介质的一个特征,而不是因为数据未向下发送到 TCP 堆栈而延迟 ACK。
参考: http: //people.na.infn.it/~garufi/didattica/CorsoAcq/Trasp/Lezione9/tcpip_ill/tcp_int.htm