2010-05-11 113 views
24

我们使用.Net和套接字。服务器正在使用Socket.Sender(bytes [])方法,因此它只是发送整个有效负载。另一方面,我们是客户使用数据。 Socket.Receive(缓冲液[])。在微软(以及其他)的所有例子中,他们似乎坚持使用8192的缓冲区大小。我们已经使用了这个大小,但是我们现在都会将数据发送到超过此缓冲区大小的客户端。套接字编程的缓冲区大小是多少?

有没有办法确定服务器的发送方法向我们发送了多少数据?什么是最好的缓冲区大小?

回答

31

即使您发送的数据超过此数量,也可能无法在一次接收呼叫中使用。

您无法确定服务器发送了多少数据 - 这是数据流的数据流,您一次只能读取数据块。您可以阅读部分服务器在一次发送呼叫中发送的内容,也可以在一次接收呼叫中从两次发送呼叫中读取数据。 8K是一个合理的缓冲区大小 - 不是很大,以至于会浪费大量内存,而且不会太小,以至于不得不使用大量浪费的接收调用。 4K或16K也可能会很好......我个人不会开始超过16K的网络缓冲区 - 我怀疑你很少会填充它们。

您可以尝试使用一个非常大的缓冲区并记录每次调用中接收到多少字节 - 这会让您知道一般有多少可用的 - 但它不会真正显示效果使用较小的缓冲区。你有什么关于使用8K缓冲区的问题?如果是性能,你有没有证据表明你的代码的这个方面是性能瓶颈?

+0

如果可能,我想增加缓冲区大小。我们正在考虑将它设置为32K,但我担心上述情况,即使我只用一次Send来发送,receive命令也不会获取所有内容。 – uriDium 2010-05-11 13:36:46

+0

对不起,我忘记提到我们正在阻止模式下这样做。虽然我没有看到它有所作为。 – uriDium 2010-05-11 13:41:10

+3

@uriDium:您应该编写代码,以便它不依赖于接收来自单个接收中的单个发送的所有内容。这不是TCP使用的模型 - 它是* stream *模型。如果您想将该流分段为不同的消息,则应该使用分隔符或为每条消息编写长度前缀,以便客户端知道要读取多少内容。 – 2010-05-11 13:53:35

1

8192会是理想的。如果你有超过这个大小的数据,那你最好用恒定长度的数据包发送数据。

服务器发送的数据大小可以使用WINSOCK中的recv函数进行检查,该函数有一个给出缓冲区长度的参数。

+0

8192不是'理想',而是一个通常有用的数字。以恒定长度的数据包发送数据并不会更好:最好尽可能快地传输数据。发送的数据量不一定与对端的'recv()'返回的值有关。这是一个流媒体协议。 – EJP 2017-04-18 23:16:57

6

这取决于你的协议。如果您希望消息超过8192字节,则应该相应地增加缓冲区大小。但请记住,该缓冲区大小仅适用于Receive的一个调用。如果您真的想要/需要,您可以多次循环Receive,并将接收到的数据复制到任意大的数据结构或缓冲区中。

另外请记住,重复调用Receive是一种很好的做法,直到您确认您已经读取了给定消息的所有数据;即使单个邮件小于您的缓冲区大小,它仍可能不会全部通过一个Receive调用检索。

4

Jon Skeet的答案不幸留下了大部分图片 - 发送缓冲区大小和您写入的管道的bandwidth-delay product

如果您尝试使用单个套接字通过大型管道发送数据,并且希望TCP填充该管道,则需要使用等同于管道带宽延迟产品的发送缓冲区大小。否则,TCP将不会填充管道,因为它不会在任何时候留下足够的'正在运行的字节'。

考虑一个速度为1千兆的连接,并且平均具有10毫秒的单向延迟。往返时间(又称,发送数据包的套接字与接收数据包ack并因此知道发送更多数据的时间间隔)通常是延迟的两倍。所以如果你有1千兆连接和20毫秒的RTT,那么如果管道被完全利用,那么这个管道在任何时间都有1个千兆/秒* 20毫秒= 2.5兆数据的飞行数据。

如果您的TCP发送缓冲区小于2.5兆字节,那么这一个套接字将永远不会完全利用管道 - 您永远不会从套接字中获得千兆/秒的性能。

如果您的应用程序使用多个套接字,那么为了充分利用这个假设的1千兆/ 20毫秒RTT管道,所有TCP发送缓冲区的聚合大小必须为2.5 MB。例如,如果使用8192字节的缓冲区,则需要306个同步TCP套接字来填充该管道。