您的位置:首页 > 理论基础 > 计算机网络

19- TCP 协议(Nagle)

2017-04-11 14:50 197 查看
前面我们所用的
unp/protocol/tools/winclient/echo_cli.cpp
程序的特别之处是它总会发送一个小分组(TCP 段,只有 41 字节)到服务器。这样的小分组在英文中称为 tinygram,在网络状态好的情况下,比如局域网中,通常不会引起什么麻烦。但是在广域网中,这样的小分组会增加网络拥塞的可能。

为了能够减少这样的 tinygram 在网络中的数量,在 TCP 协议栈中,默认使用了 Nagle 算法。

1. Nagle 算法

Nagle 算法要求:

一个 TCP 连接上最多只能有一个未被确认的未完成的小分组,在它到达目的地前,不能发送其它分组。

在上一个小分组未到达目的地前,即还未收到它的 ack 前,TCP 会收集后来的小分组。当上一个小分组的 ack 收到后,TCP 就将收集的小分组合并成一个大分组发送出去。

在广域网中,一般网络延时都比较大,小分组发送出去后,可能要等很久才会收到 ack,因此,在收到 ack 前,发送方可能会累积好多好多未发送的小分组。



图1 Nagle 算法如何处理小分组

在图 1 中,客户端首先发送了一个字符
l
给服务器,在收到服务器的回应前,客户端又发送了三个分组,根据 Nagle 算法规则,在未收到 ack 前,这些小分组都不能发出去。收到 ack 后,tcp 将这三个小分组合并成一个,一次性发出去。

2. 实验 1(开启 Nagle 算法)

默认情况下 Nagle 算法就是开启的。

在图 1 中,假设往返时间是 16ms,要想在这 16ms 里连续发送 4 个字符
l
,
o
,
v
,
e
几乎是不可能的,这意味着我们每秒打字速度要超过 250 个左右,16 ms 里发送至少 2 个字符,打字速度也得要超过每秒 60 个。那么如何在实验中模拟快速发送字符呢?

客户端 echo_client.cpp 提供了一个选项,它能帮我们在键入一个字符时,连续将此字符发送多次。比如键入字符
x
,echo_client.cpp 会在极短时间内将
x
发送很多次。

客户端路径:
unp/protocol/tools/winclient/echo_client.cpp
,部署在 windows 上。

服务器路径:
unp/protocol/tools/tcpserver/echo_serv.c
,部署在 Linux 上。

2.1 实验步骤

在 Linux 上启动服务器 echo_serv

$ ./echo_serv 192.168.80.130 8000


在 Windows 上打开 OmniPeek 抓包

Windows 上启动 echo_client.exe

// 注意 echo_client 后面又加了个参数 5,表示将输入的字符连续发送 5 次
echo_client.exe 192.168.80.130 8000 5


接下来,我在 client 中键入了一个字符
x
,然后按
q
键结束。

2.2 抓包结果



图2 OmniPeek 抓的数据

图 2 中,客户端首先发送了一个字符
x
过去,接下来等待 ack,在此期间,客户端又请求发送了四个
x
,TCP 将这些后来的小分组收集,当收到 ack 后,将这 4 个
x
合并成了一个分组一次发送出去。

3. 实验 2(关闭 Nagle 算法)

这一次我们关闭 Nagle 算法。

和实验 1 不同的地方在于,客户端启动的时候,再加一个参数,NONAGLE.

// 启动客户端

echo_client.exe 192.168.80.130 8000 5 NONAGLE


同样的在客户端中输入一个字符
x
,此时客户端会帮我们连续发送 5 次
x
,然后按
q
退出。抓包结果如下:



图3 没有 Nagle 算法的情况下,客户端发数据的结果

从图 3 中可以看到,红色框框包含的那 5 个数据包,在极短的时间内被发送出去,TCP 在发送第一个包后,并没有等待对方回送的确认。

4. 总结

掌握 Nagle 算法的规则

有 Nagle 算法和无 Nagle 有什么不同
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tcp nagle unp