是否有通过网络发送数据的最佳字节大小?

我假设100个字节太小,并且可以减慢所有写入的较大文件传输速度,但像1MB这样的东西似乎可能太多了。 有没有人对每次写入的最佳字节块有什么建议,以便通过网络发送数据?

为了详细说明,我正在实现通过网络连接发送数据并显示正在发送的数据的进度。 我注意到如果我每次写入大约100个字节发送大文件,它非常慢,但进度条非常好。 但是,如果我每次写入发送1M,那么速度要快得多,但由于发送的块越大,进度条就不能正常工作。

如果可以,只需让IP堆栈处理它; 大多数操作系统已经内置了很多优化。例如,Vista会动态地改变各种参数以最大化吞吐量; 猜测算法不太可能有益。

在高阶语言中尤其如此,远离实际的线路,如C#; 你和实际的TCP / IP数据包之间有足够的层,我希望你的代码对吞吐量的影响相对较小。

最糟糕的是,在各种情况下为自己测试各种消息大小; 很少有解决方案是一刀切的。

不,没有通用的最佳字节大小。

TCP数据包会受到碎片的影响,虽然假设从这里到目的地的所有内容都是真正的以太网并且数据包大小很大,但实际上即使您可以获得所有单个网络的数据包大小也是如此需要,您发送的每个数据包可能会通过互联网采取不同的路径。

这不是你可以“解决”的问题,并且没有通用的理想尺寸。

尽可能快地将数据提供给操作系统和TCP / IP堆栈,它将动态调整数据包大小到网络连接(您应该看到他们用于此优化的代码 – 它真的非常有趣。至少在更好的堆栈上。)

但是,如果您控制所使用的所有网络和堆栈以及客户端/服务器之间的所有网络和堆栈,那么您可以进行一些手动调整。 但一般来说,在我建议您接近之前,您必须非常好地掌握网络和发送的数据。

-亚当

如果您使用的是以太网TCP / IP,则最大数据包大小约为1500字节。 如果您尝试一次发送多个数据,数据将被分成多个数据包,然后再通过线路发送出去。 如果应用程序中的数据已经打包,那么您可能希望选择一个小于1500的数据包大小,以便在发送完整数据包时,底层堆栈不必将其分解。 例如,如果您执行的每个发送都是1600字节,则TCP堆栈必须为每个发送发送两个数据包,第二个数据包通常为空。 这效率很低。

话虽如此,我不太了解这对性能产生的明显影响。

我相信你的问题是你使用阻塞套接字而不是非阻塞套接字。

当您使用阻塞套接字并发送1M数据时,网络堆栈可以等待所有数据放入缓冲区,如果缓冲区已满,您将被阻止,进度条将等待整个1M数据接受缓冲区,这可能需要一段时间,你的进度条将是跳跃的。

但是如果你使用非阻塞套接字,那么你使用的任何缓冲区大小都不会阻塞,你需要自己用select / poll / epoll / whatever-works-on-your-platform进行等待(选择是最便携的) )。 通过这种方式,您的进度条将快速更新并反映最准确的信息。

请注意,在发送方处,进度条会以任何方式部分中断,因为内核将缓冲某些数据,并且在对方确实收到数据之前您将达到100%。 唯一的解决方法是,如果您的协议包含对接收方接收的数据量的回复。

正如其他人所说,第二次猜测操作系统和网络几乎是徒劳的,如果你继续使用阻塞套接字选择一个足够大的大小来包含比单个数据包更多的数据,这样你就不会在数据包中发送太少的数据。这将不必要地降低您的吞吐量。 我会选择类似4K的东西,一次至少包含两个数据包。

我将添加的一件事是,对于给定的以太网连接,将小数据包作为大数据包发送所需的时间相同。 正如其他人所说:如果你只是发送一个数据流,让系统处理它。 但是如果你担心来回的个别短信,一个典型的以太网数据包大约是1500字节 – 只要你把它保持在你应该是好的。

您需要使用Path MTU Discovery ,或使用良好的默认值(即小于1500字节)。

创建一个名为CalcChunkSize的函数向您的类添加一些私有变量:

Private PreferredTransferDuration As Integer = 1800 ' milliseconds, the timespan the class will attempt to achieve for each chunk, to give responsive feedback on the progress bar. Private ChunkSizeSampleInterval As Integer = 15 ' interval to update the chunk size, used in conjunction with AutoSetChunkSize. Private ChunkSize As Integer = 16 * 1024 ' 16k by default Private StartTime As DateTime Private MaxRequestLength As Long = 4096 ' default, this is updated so that the transfer class knows how much the server will accept 

在每次下载块之前,检查是否有时间使用ChunkSizeSampleInterval计算新的chunksize

  Dim currentIntervalMod As Integer = numIterations Mod Me.ChunkSizeSampleInterval If currentIntervalMod = 0 Then Me.StartTime = DateTime.Now ElseIf currentIntervalMod = 1 Then Me.CalcChunkSize() End If 

在下载循环之外和每个下载的块设置为numIterations + = 1之后,numIterations设置为0

让CalcChunkSize执行此操作:

 Protected Sub CalcAndSetChunkSize() ' chunk size calculation is defined as follows ' * in the examples below, the preferred transfer time is 1500ms, taking one sample. ' * ' * Example 1 Example 2 ' * Initial size = 16384 bytes (16k) 16384 ' * Transfer time for 1 chunk = 800ms 2000 ms ' * Average throughput / ms = 16384b / 800ms = 20.48 b/ms 16384 / 2000 = 8.192 b/ms ' * How many bytes in 1500ms? = 20.48 * 1500 = 30720 bytes 8.192 * 1500 = 12228 bytes ' * New chunksize = 30720 bytes (speed up) 12228 bytes (slow down from original chunk size) ' Dim transferTime As Double = DateTime.Now.Subtract(Me.StartTime).TotalMilliseconds Dim averageBytesPerMilliSec As Double = Me.ChunkSize / transferTime Dim preferredChunkSize As Double = averageBytesPerMilliSec * Me.PreferredTransferDuration Me.ChunkSize = CInt(Math.Min(Me.MaxRequestLength, Math.Max(4 * 1024, preferredChunkSize))) ' set the chunk size so that it takes 1500ms per chunk (estimate), not less than 4Kb and not greater than 4mb // (note 4096Kb sometimes causes problems, probably due to the IIS max request size limit, choosing a slightly smaller max size of 4 million bytes seems to work nicely) End Sub 

然后在请求下一个块时使用ChunkSize。

我在Tim_mackey的“使用MTOM Web服务和.Net 2.0发送文件”中发现了这一点,我发现自己动态计算最有效的chunksize非常有用。

整个源代码如下: http : //www.codeproject.com/KB/XML/MTOMWebServices.aspx

作者: http : //www.codeproject.com/script/Membership/Profiles.aspx?mid = 321767

您可以做的一个经验测试,如果您还没有,当然是使用嗅探器(tcpdump,Wireshark等),并查看使用其他软件进行上传/下载时实现的数据包大小。 这可能会给你一个暗示。

这是您需要的公式:

 int optimalChunkSize = totalDataSize / progressBar1.Width; 

使用此function,您发送的每个块都会将进度条增加1个像素。 就用户反馈而言,比这更小的块大小毫无意义。