TCP传输小数据包效率问题

当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字节左右,用了半个多小时才全部传到服务器。

分析:
因为客户端没有设置TCP_NODELAY选项,Nagle算法强制TCP栈在发送数据包之前等待前一个数据包的ACK确认信息。然而,客户端设置SO_SNDBUF为0,禁用了内核缓冲区。因此,10000个Send调用只能一个数据包一个数据包的发送和确认,由于下列原因,每个ACK确认信息被延迟200毫秒:
1、当服务器获取到一个数据包,启动一个200毫秒的计时器。
2、服务端不需要向客户端发送任何数据,所以,ACK确认信息不能被发回的数据包顺路携带。
3、客户端在没有收到前一个数据包的确认信息前,不能发送数据包。
4、服务端的计时器超时后,ACK确认信息被发送到客户端。

如何提高性能:
在这个设计中存在两个问题。第一,存在延时问题。客户端需要能够在200毫秒内发送两个数据包到服务端。因为客户端默认情况下使用Nagle算法,应该使用默认的内核缓冲区,不应该设置SO_SNDBUF为0。一旦TCP栈拼接起来的数据包超过MTU值,这个数据包会立即被发送,不用等待前一个ACK确认信息。第二,这个设计方案对每一个如此小的的数据包都调用一次Send。发送这么小的数据包是不很有效率的。在这种情况下,应该把每个记录补充到100字节并且每次调用Send发送80个记录。为了让服务端知道一次总共发送了多少个记录,客户端可以在记录前面带一个头信息。

案例二:
一个Winsock TCP客户端程序打开两个连接和一个提供股票报价服务的Winsock TCP服务端通信。第一个连接作为命令通道用来传输股票编号到服务端。第二个连接作为数据通道用来接收股票报价。两个连接被建立后,客户端通过命令通道发送股票编号到服务端,然后在数据通道上等待返回的股票报价信息。客户端在接收到第一个股票报价信息后发送下一个股票编号请求到服务端。客户端和服务端都没有设置SO_SNDBUF和TCP_NODELAY选项。

性能:
测试中发现,客户端每秒只能获取到5条报价信息。

分析:

这个设计方案一次只允许获取一条股票信息。第一个股票编号信息通过命令通道发送到服务端,立即接收到服务端通过数据通道返回的股票报价信息。然后,客户端立即发送第二条请求信息,send调用立即返回,发送的数据被复制到内核缓冲区。然而,TCP栈不能立即投递这个数据包到网络,因为没有收到前一个数据包的ACK确认信息。200毫秒后,服务端的计时器超时,第一个请求数据包的ACK确认信息被发送回客户端,客户端的第二个请求包才被投递到网络。第二个请求的报价信息立即从数据通道返回到客户端,因为此时,客户端的计时器已经超时,第一个报价信息的ACK确认信息已经被发送到服务端。这个过程循环发生。

如何提高性能:
在这里,两个连接的设计是没有必要的。如果使用一个连接来请求和接收报价信息,股票请求的ACK确认信息会被返回的报价信息立即顺路携带回来。要进一步的提高性能,客户端应该一次调用Send发送多个股票请求,服务端一次返回多个报价信息。如果由于某些特殊原因必须要使用两个单向的连接,客户端和服务端都应该设置TCP_NODELAY选项,让小数据包立即发送而不用等待前一个数据包的ACK确认信息。

提高性能的建议:
上面两个案例说明了一些最坏的情况。当设计一个方案解决大量的小数据包发送和接收时,应该遵循以下的建议:
1、如果数据片段不需要紧急传输的话,应用程序应该将他们拼接成更大的数据块,再调用Send。因为发送缓冲区很可能被复制到内核缓冲区,所以缓冲区不应该太大,通常比8K小一点点是很有效率的。只要Winsock内核缓冲区得到一个大于MTU值的数据块,就会发送若干个数据包,剩下最后一个数据包。发送方除了最后一个数据包,都不会被200毫秒的计时器触发。
2、如果可能的话,避免单向的Socket数据流接连。
3、不要设置SO_SNDBUF为0,除非想确保数据包在调用Send完成之后立即被投递到网络。事实上,8K的缓冲区适合大多数情况,不需要重新改变,除非新设置的缓冲区经过测试的确比默认大小更高效。
4、如果数据传输不用保证可靠性,使用UDP。

时间: 2024-08-07 03:44:46

TCP传输小数据包效率问题的相关文章

java-Java Socket 读取TCP服务端数据包不完整

问题描述 Java Socket 读取TCP服务端数据包不完整 Java Socket 读取TCP服务端数据包不完整:除了利用数据包大小循环读取输入流的得到完整的数据外,还有其他什么方法? 数据包在网络传输的过程中,数据传递到客户端基本处于"无序"态.除了开辟一块内存按数据包的顺序存放外,还有其他更好的方案么? 解决方案 TCP 因为是长连接的,肯定是有序的.数据接收不完整,这种现象在通讯中很常见的,是必须代码处理. 解决方案二: TCP是有序的吧?UDP才是无序的. 解决方案三: T

ios-iOS视频解码问题,通过tcp传递的数据包播放

问题描述 iOS视频解码问题,通过tcp传递的数据包播放 最近在做一个项目:以外接摄像头为服务器,设备传递数据,通过tcp协议接收后数据后播放并且转码.大神给点思路,知道要用ffpeng或kxmovie,关键是怎么把tcp过来的数据放到里面让它解析? 解决方案 传输的时候用二进制数据,接收后也是二进制还原,然后传给ffpeg等解析.

关于TCP封包、粘包、半包

关于Tcp封包 很多朋友已经对此作了不少研究,也花费不少心血编写了实现代码和blog文档.当然也充斥着一些各式的评论,自己看了一下,总结一些心得. 首先我们学习一下这些朋友的心得,他们是: http://blog.csdn.net/stamhe/article/details/4569530 http://www.cppblog.com/tx7do/archive/2011/05/04/145699.html //------ 当然还有太多,很多东西粘来粘区也不知道到底是谁的原作,J 看这些朋友

路由器网络中数据包传输分析

本篇介绍一个基础的知识,关于数据包在路由器中是如何进行传输和交换的,只要明白这点,那么对你配置出一个好的网络环境会有很大的帮助. 一.输入的问题 1.原始套接口可以接收到任何TCP或UDP报文. 2.要想接收到原始套接口,首先要接收的数据包必须有一个完整的.正确的IP头,否则不能通过ip_rcv()中的包头检查和检验和验证. 3.在原始套接口接收的数据包过程中,内核会对接收的IP包进行校验和验证,但不会对IP包以后的任何字段进行检测和验证.如,我们创建原始套接口时,所指定的protocol参数为

使用无线网络数据包对无线网络安全进行分析

本文阐述的是利用无线网络数据包来对无线网络安全的正确分析,在无线网络中,建立连接并不像连接有线网络那样简单,物理安全也没有阻止未经授权人员进入设备室那样容易,甚至在接入点总方向的小问题都可能让你崩溃.也就是说,保护无线网络安全将成为未来安全行业的挑战.在这篇文章中,我们将探讨解决利用数据包分析无线安全问题的实用技巧,首先我们将展示正确连接无线网络数据包的方法,收集到正确数据后,我们将探讨不同的分析技术,包括分析WEP/WPA认证.过滤加密流量以及寻找恶意接入点等.捕获无线数据包从数据包 来看,无

Linux防火墙数据包捕获模块

一.防火墙概述 网络防火墙技术是一种用来加强网络之间访问控制,防止外部网络用户以非法手段通过外部网络进入内部网络,访问内部网络资源,保护内部网络操作环境的特殊网络互联设备.它对两个或多个网络之间传输的数据包按照一定的安全策略来实施检查,以决定网络之间的通信是否被允许,并监视网络运行状态. 根据防火墙所采用的技术不同,可以将它分为四种基本类型:包过滤型.网络地址转换-NAT.代理型和监测型.包过滤型产品是防火墙的初级产品,其技术依据是网络中的分包传输技术.包过滤技术的优点是简单实用,实现成本较低

《Wireshark数据包分析实战(第2版)》—第6章6.2节互联网协议

6.2 互联网协议位于OSI模型中第3层的协议的主要目的就是使得网络间能够互联通信.正如你所知道的,MAC地址被用来在第2层处理单一网络中的通信.与其类似,第3层则负责跨网络通信的地址.在这层上工作的不止一个协议,但最普遍的还是互联网协议(IP).在此,我们将介绍在RFC 791中所定义的IP协议版本4(IPv4). 如果网络中的所有设备仅使用集线器或者交换机进行连接,那么这个网络称为局域网.如果你想将两个局域网连接起来,你可以使用路由器办到这一点.在复杂的网络中,可能会包含成千上万的局域网,而

基于数据包分析的大数据技术解决网络安全问题

1.网络攻击简介 网络攻击是利用网络存在的漏洞和安全缺陷对网络系统的硬件.软件及其系统中的数据进行的攻击.网络信息系统所面临而对威胁来自很多方面,而且会随着时间的变化而变化.从宏观上看,这些威胁可分为人为威胁和自然威胁. 自然威胁来自于各种自然灾害.恶劣的场地环境.电磁干扰.网络设备的自然老化等.这些威胁是无目的性的,但会对网络通信系统造成损害,威胁通信安全. 而人为威胁是对网络信息系统的人为攻击,通常是通过寻找系统的弱点,以非授权方式达到破坏.欺骗和窃取数据信息等目的.两者相比,精心设计的人为

wireshark抓取本地回环数据包和取出数据的方法

 这篇文章主要介绍了wireshark抓取本地回环数据包和取出数据的方法,需要的朋友可以参考下 一:The NPF driver isn't running   这个错误是因为没有开启NPF服务造成的.   NPF即网络数据包过滤器(Netgroup Packet Filter,NPF)是Winpcap的核心部分,它是Winpcap完成困难工作的组件.它处理网络上传输的数据包,并且对用户级提供可捕获(capture).发送(injection)和分析性能(analysis capabilitie