Nagle算法 TCP_NODELAY和TCP_CORK
Nagle算法
根据创建者John Nagle命名。该算法用于对缓冲区内的一定数量的消息进行自动连接。该处理过程(称为Nagling),通过减少必须发送的封包的数量,提高了网络应用 程序系统的效率。Nagle算法,由Ford Aerospace And Communications Corporation Congestion Control in IP/TCP internetworks(IETF RFC 896)(1984)定义,最初是用于缓冲Ford的私有TCP/IP网络拥塞情况,不过被广泛传播开来。Nagle的文档定义了一种他称之为小封包问题的解决方法。当某个应用程序每次只产生一字节的数据,就会导致网络由于这样的小封包而过载(该情况通 常被称为“发送端SB窗口并发症”),从而产生该问题。一个源自键盘的单一字符-1字节的数据-可能导致一个41字节的封包被传送,该封包包含了1字节的 有用数据和40字节的头部数据。这种4000%过载的情况,在像APRANET这样只有轻负载的网络中是可以接受的,但在像Ford这样的负载很重的网 络中,可能强制重传,导致封包丢失,并且通过过度拥挤交换节点和网关降低了传播速度。更进一步,当连接被丢弃时,吞吐量可能被降低。Nagle算法-通常 的实现方法是在一个TCP程序中插入两行代码-在发送方,对标识为没有回应的数据进行缓冲(存储)(这句怪怪的,其实应该是对未发送数据按顺序进行缓冲,在发送时进行拼接)。顺序发送的数据将被保持到接收到被标识数据的回应或者一整包有价值的数据需要被发送。
虽然Nagle算法用于解决Ford网络内产生的问题,但同样的问题也出现在APRANet。通过网络,Nagling被广泛实现,包括 internet,并且产生了巨大的效用-虽然某些时候在高交互性环境如一些C/S情况下不希望进行该处理。在这种情况下,可以通过 TCP_NODELAY套接字选项关闭Nagling。
注:Nagle虽然解决了小封包问题,但也导致了较高的不可预测的延迟,同时降低了吞吐量。
实际上这就的你动手来自己实现以下Nagle算法了。实际上Nagle算法并不是很复杂,他的主要职责是数据的累积,实际上有两个门槛:一个就是缓 冲区中的字节数达到了一定量,另一个就是等待了一定的时间(一般的Nagle算法都是等待200ms);这两个门槛的任何一个达到都必须发送数据了。一般 情况下,如果数据流量很大,第二个条件是永远不会起作用的,但当发送小的数据包时,第二个门槛就发挥作用了,防止数据被无限的缓存在缓冲区不是好事情哦。 了解了TCP的Nagle算法的原理之后我们可以自己动手来实现一个类似的算法了,在动手之前我们还要记住一个重要的事情,也是我们动手实现Nagle算 法的主要动机就是我想要紧急发送数据的时候就要发送了,所以对于上面的两个门槛之外还的增加一个门槛就是紧急数据发送。现在可以开始工作了,我们这里主要给出思路:
首先我们必须在SOCKET之上再建立一层,来定义我们的自己的传输控制,我们的Nagle算法也是在这层里面实现的。 Disable哪个TCP的Nagle算法,都自己动手写了,要它干吗 使 用Select函数来查看是否可以发送数据,当然我们实质是否可写的fd_set的时候需要加入我们的三个门槛,首先是按照字节和紧急数据来检查,一般情 况下这两个条件就搞定了,然后再按照时间来决定。我们可是使用一个累积字节记数器和一个等待时间计时器。累积字节记数器在每次添加数据到我们的控制层的时 候就累加一下,发送完毕的时候减去响应的字节数;而计时器在第一次将数据提交给控制层的时候启动(可以使用Windows的GetTickcount来得 到当前的时间),然后在每次发送数据完毕的时候重新复位一下。 实际上这样就已经实现了Nagle算法,而且不需要经常调用GetTickCount而降低了系统的性能。
TCP_CORK
TCP链接的过程中,默认开启Nagle算法,进行小包发送的优化。优化网络传输,兼顾网络延时和网络拥塞。这个时候可以置位TCP_NODELAY关闭Nagle算法,有数据包的话直接发送保证网络时效性。
在进行大量数据发送的时候可以置位TCP_CORK关闭Nagle算法保证网络利用性。尽可能的进行数据的组包,以最大mtu传输,如果发送的数据包大小过小则如果在0.6~0.8S范围内都没能组装成一个MTU时,直接发送。如果发送的数据包大小足够间隔在0.45内时,每次组装一个MTU进行发送。如果间隔大于0.4~0.8S则,每过来一个数据包就直接发送。
下面摘自:http://blog.csdn.net/lin49940/archive/2009/07/26/4382303.aspx
TCP_NODELAY 选项
设置该选项: public void setTcpNoDelay(boolean on) throws SocketException
读取该选项: public boolean getTcpNoDelay() throws SocketException
默认情况下, 发送数据采用Negale 算法. Negale 算法是指发送方发送的数据不会立即发出,而是先放在缓冲区, 等缓存区满了再发出. 发送完一批数据后, 会等待接收方对这批数据的回应,然后再发送下一批数据. Negale 算法适用于发送方需要发送大批量数据, 并且接收方会及时作出回应的场合, 这种算法通过减少传输数据的次数来提高通信效率.
如果发送方持续地发送小批量的数据, 并且接收方不一定会立即发送响应数据, 那么Negale算法会使发送方运行很慢. 对于GUI 程序, 如网络游戏程序(服务器需要实时跟踪客户端鼠标的移动), 这个问题尤其突出. 客户端鼠标位置改动的信息需要实时发送到服务器上, 由于Negale 算法采用缓冲, 大大减低了实时响应速度, 导致客户程序运行很慢.
下面摘自http://hi.baidu.com/dirlt/blog/item/5ea4be1795d30b03c83d6d7f.html
TCP_NODELAY和TCP_CORK
这里了解一下问题的背景就好理解了[不考虑滑动窗口加入,只是说packet的组织]
1.历史上TCP是每发送一次包等待一个ACK然后下一个
2.但是在一些交互式应用下比如Telnet,结果就是我们每按一次键就会发送一个packet.每一个字符配一个TCP头效率不高,那个Nagle算法出来了。发送方法送数据A时然后再等待接受方的ACK时,积累本地收集到的所有TCP数据包然后一次性发送。但是很明显Nagle算法不利于交互式情景
3.但是现代应用下面还是存在交互式应用的,所以有时候我们需要关闭Nagle那么可以设置TCP_NODELAY
4.但是Nagle组织包的长度是由系统决定的,有时候我们知道我们会每个1分钟产生1字节,共1000字节。如果完全由Nagle算法来发送的话,可能还是会1字节1字节发送[这是一种极端情况,假设返回ACK时间不是很长]。这个时候首先设置TCP_CORK能够阻塞住TCP[尽量阻塞住],等我们write完1000字节之后,取消TCP_CORK,这个时候就能够将1000字节一次发出TCP_NODELAY和TCP_CORK都是禁用Nagle算法,只不过NODELAY完全关闭而TCP_CORK完全由自己决定
发送时机。Linux文档上说两者不要同时设置。