我们正在使用.Net和套接字。服务器使用Socket.Sender(bytes [])方法,因此它只发送整个有效负载。另一方面,我们是消费数据的客户。 Socket.Receive(缓冲液[])。在Microsoft(和其他人)的所有示例中,他们似乎都坚持使用8192的缓冲区大小。我们使用了这个大小,但我们不时地将数据发送到超过此缓冲区大小的客户端。
有没有办法确定服务器发送方法发送给我们的数据量?什么是最好的缓冲区大小?
答案 0 :(得分:37)
即使您发送的数据多于此数据,也可能无法在一次接收调用中使用。
您无法确定服务器发送了多少数据 - 它是数据的流,您只是一次只读取数据块。您可以阅读服务器在一个发送呼叫中发送的部分,或者您可以从一个接收呼叫中的两个发送呼叫中读取数据。 8K是一个合理的缓冲区大小 - 不是那么大,你会浪费大量的内存,而不是那么小,你将不得不使用大量浪费的接收调用。 4K或16K很可能也很好......我个人不会开始超过16K的网络缓冲区 - 我怀疑你很少填充它们。
您可以尝试使用一个非常大的缓冲区并记录每次调用中接收的字节数 - 这可以让您了解一般可用的数量 - 但它不会真的显示使用较小缓冲区的效果。您对使用8K缓冲区有什么顾虑?如果是性能,您是否有证据表明代码的这一方面是性能瓶颈?
答案 1 :(得分:12)
Jon Skeet的回答不幸遗留了大部分图片 - 发送缓冲区大小以及您正在写入的管道的bandwidth-delay product。
如果您尝试使用单个套接字通过大型管道发送数据,并且您希望TCP填充该管道,则需要使用等于管道的带宽延迟乘积的发送缓冲区大小。否则,TCP将不会填充管道,因为它不会在飞行中留下足够的字节数'在任何时候。
考虑速度为1千兆位的连接,平均单向延迟为10毫秒。往返时间(也就是说,套接字发送数据包之间经过的时间和收到该数据包的确认时间因此知道发送更多数据的时间)通常是延迟的两倍。
因此,如果你有1千兆位连接,RTT为20毫秒,那么如果它完全被利用,那么该管道在飞行中始终具有1千兆位/秒* 20毫秒== 2.5兆字节的数据
如果你的TCP发送缓冲区小于2.5兆字节,那么那个套接字永远不会完全利用管道 - 你的套接字永远不会达到千兆位/秒的性能。
如果您的应用程序使用多个套接字,则所有TCP发送缓冲区的聚合大小必须为2.5 MB,以便充分利用此假设的1千兆位/ 20毫秒RTT管道。例如,如果使用8192字节的缓冲区,则需要306个并发的TCP套接字来填充该管道。
答案 2 :(得分:7)
这取决于您的协议。如果您期望超过8192字节的消息,则应相应地增加缓冲区大小。但请记住,此缓冲区大小仅适用于Receive
的一次调用。如果您真的需要/需要,可以多次循环Receive
并将接收的数据复制到任意大的数据结构或缓冲区中。
另请注意,最好重复调用Receive
,直到您确认已阅读给定邮件的所有数据为止;即使单个邮件小于缓冲区大小,单个Receive
调用也可能无法检索到所有邮件。
答案 3 :(得分:0)
8192将是理想的。如果您的数据超过此大小,最好以恒定长度的数据包发送数据。
可以使用WINSOCK中的recv函数检查服务器发送的数据大小,该函数的参数为缓冲区长度。
答案 4 :(得分:0)
与Microsoft的关系不大,但是我只是在尝试使用TCP端口(不是Unix域套接字)的C ++线程回显服务器来查看吞吐量。对具有各种缓冲区大小的4M输入进行计时会产生以下结果:
1024 - real 0m0,102s; user 0m0,018s; sys 0m0,009s
2048 - real 0m0,112s; user 0m0,017s; sys 0m0,009s
8192 - real 0m0,163s; user 0m0,017s; sys 0m0,007s
256 - real 0m0,101s; user 0m0,019s; sys 0m0,008s
16 - real 0m0,144s; user 0m0,016s; sys 0m0,010s
似乎以1024字节的块读取可以减少TCP开销,而处理时间(只是回显输入)不受缓冲区大小的影响。 8192字节似乎很高,而实际上很低的值(例如16)也不好。