首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

关于网络编程中MTU、TCP、UDP优化配置的一些总结(2)

关于网络编程中MTU、TCP、UDP优化配置的一些总结(2)

4. Nagle算法与CORK算法区别
     Nagle算法和CORK算法非常类似,但是它们的着眼点不一样,Nagle算法主要避免网络因为太多的小包(协议头的比例非常之大)而拥塞,而CORK算法则是为了提高网络的利用率,使得总体上协议头占用的比例尽可能的小。如此看来这二者在避免发送小包上是一致的,在用户控制的层面上,Nagle算法完全不受用户socket的控制,你只能简单的设置TCP_NODELAY而禁用它,CORK算法同样也是通过设置或者清除TCP_CORK使能或者禁用之,然而Nagle算法关心的是网络拥塞问题,只要所有的ACK回来则发包,而CORK算法却可以关心内容,在前后数据包发送间隔很短的前提下(很重要,否则内核会帮你将分散的包发出),即使你是分散发送多个小数据包,你也可以通过使能CORK算法将这些内容拼接在一个包内,如果此时用Nagle算法的话,则可能做不到这一点。
    实际上Nagle算法并不是很复杂,他的主要职责是数据的累积,实际上有两个门槛:一个就是缓 冲区中的字节数达到了一定量,另一个就是等待了一定的时间(一般的Nagle算法都是等待200ms);这两个门槛的任何一个达到都必须发送数据了。一般 情况下,如果数据流量很大,第二个条件是永远不会起作用的,但当发送小的数据包时,第二个门槛就发挥作用了,防止数据被无限的缓存在缓冲区不是好事情哦。 了解了TCP的Nagle算法的原理之后我们可以自己动手来实现一个类似的算法了,在动手之前我们还要记住一个重要的事情,也是我们动手实现Nagle算 法的主要动机就是我想要紧急发送数据的时候就要发送了,所以对于上面的两个门槛之外还的增加一个门槛就是紧急数据发送。
    对于我现在每秒钟10次数据发送,每次数据发送量固定在85~100字节的应用而言,如果采用默认的开启Nagle算法,我在发送端,固定每帧数据85个,间隔100ms发送一次,我在接受端(阻塞方式使用)接受的数据是43 138交替出现,可能就是这个算法的时间阈值问题,如果关闭Nagle算法,在接收端就可以保证数据每次接收到的都是85帧。
    Nagle算法适用于小包、高延迟的场合,而对于要求交互速度的b/s或c/s就不合适了。socket在创建的时候,默认都是使用Nagle算法的,这会导致交互速度严重下降,所以需要setsockopt函数来设置TCP_NODELAY为1.不过取消了Nagle算法,就会导致TCP碎片增多,效率可能会降低。
关闭nagle算法,以免影响性能,因为控制时控制端要发送很多数据量很小的数据包,需要马上发送。
const char chOpt = 1;
int nErr = setsockopt(pContext->m_Socket, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char));
if (nErr == -1)
{
    TRACE(_T("setsockopt() error\n"),WSAGetLastError());
    return;
}
setsockopt(sockfd, SOL_TCP, TCP_CORK, &on, sizeof(on)); //set TCP_CORK


TCP传输小数据包效率问题
摘要:当使用TCP传输小型数据包时,程序的设计是相当重要的。如果在设计方案中不对TCP数据包的
延迟应答,Nagle算法,Winsock缓冲作用引起重视,将会严重影响程序的性能。这篇文章讨论了这些
问题,列举了两个案例,给出了一些传输小数据包的优化设计方案。
背景:当Microsoft TCP栈接收到一个数据包时,会启动一个200毫秒的计时器。当ACK确认数据包
发出之后,计时器会复位,接收到下一个数据包时,会再次启动200毫秒的计时器。为了提升应用程序
在内部网和Internet上的传输性能,Microsoft TCP栈使用了下面的策略来决定在接收到数据包后
什么时候发送ACK确认数据包:
1、如果在200毫秒的计时器超时之前,接收到下一个数据包,则立即发送ACK确认数据包。
2、如果当前恰好有数据包需要发给ACK确认信息的接收端,则把ACK确认信息附带在数据包上立即发送。
3、当计时器超时,ACK确认信息立即发送。
为了避免小数据包拥塞网络,Microsoft TCP栈默认启用了Nagle算法,这个算法能够将应用程序多次
调用Send发送的数据拼接起来,当收到前一个数据包的ACK确认信息时,一起发送出去。下面是Nagle
算法的例外情况:
1、如果Microsoft TCP栈拼接起来的数据包超过了MTU值,这个数据会立即发送,而不等待前一个数据
包的ACK确认信息。在以太网中,TCP的MTU(Maximum Transmission Unit)值是1460字节。
2、如果设置了TCP_NODELAY选项,就会禁用Nagle算法,应用程序调用Send发送的数据包会立即被
投递到网络,而没有延迟。
为了在应用层优化性能,Winsock把应用程序调用Send发送的数据从应用程序的缓冲区复制到Winsock
内核缓冲区。Microsoft TCP栈利用类似Nagle算法的方法,决定什么时候才实际地把数据投递到网络。
内核缓冲区的默认大小是8K,使用SO_SNDBUF选项,可以改变Winsock内核缓冲区的大小。如果有必要的话,
Winsock能缓冲大于SO_SNDBUF缓冲区大小的数据。在绝大多数情况下,应用程序完成Send调用仅仅表明数据
被复制到了Winsock内核缓冲区,并不能说明数据就实际地被投递到了网络上。唯一一种例外的情况是:
通过设置SO_SNDBUT为0禁用了Winsock内核缓冲区。
Winsock使用下面的规则来向应用程序表明一个Send调用的完成:
1、如果socket仍然在SO_SNDBUF限额内,Winsock复制应用程序要发送的数据到内核缓冲区,完成Send调用。
2、如果Socket超过了SO_SNDBUF限额并且先前只有一个被缓冲的发送数据在内核缓冲区,Winsock复制要发送
的数据到内核缓冲区,完成Send调用。
3、如果Socket超过了SO_SNDBUF限额并且内核缓冲区有不只一个被缓冲的发送数据,Winsock复制要发送的数据
到内核缓冲区,然后投递数据到网络,直到Socket降到SO_SNDBUF限额内或者只剩余一个要发送的数据,才
完成Send调用。
案例1
一个Winsock TCP客户端需要发送10000个记录到Winsock TCP服务端,保存到数据库。记录大小从20字节到100
字节不等。对于简单的应用程序逻辑,可能的设计方案如下:
1、客户端以阻塞方式发送,服务端以阻塞方式接收。
2、客户端设置SO_SNDBUF为0,禁用Nagle算法,让每个数据包单独的发送。
3、服务端在一个循环中调用Recv接收数据包。给Recv传递200字节的缓冲区以便让每个记录在一次Recv调用中
被获取到。
性能:
在测试中发现,客户端每秒只能发送5条数据到服务段,总共10000条记录,976K字节左右,用了半个多小时
才全部传到服务器。
继承事业,薪火相传
很不错的测试的帖子,路过帮顶
返回列表