我假设100个字节太小,并且可以减慢所有写入的较大文件传输速度,但像1MB这样的东西似乎可能太多了。有没有人建议每次写入的最佳字节块用于通过网络发送数据?
为了详细说明,我正在实现通过网络连接发送数据并显示正在发送的数据进度的内容。我注意到如果我每次写入大约100个字节发送大文件,它非常慢,但进度条非常好。但是,如果我每次写入发送1M,那么速度要快得多,但由于发送了更大的块,进度条不能很好地工作。
答案 0 :(得分:6)
如果可以,只需让IP堆栈处理它;大多数操作系统已经内置了很多优化功能。例如,Vista会动态改变各种参数以最大化吞吐量;猜测算法不太可能有益。
在高阶语言中尤其如此,远离实际线路,如C#;你和实际的TCP / IP数据包之间有足够的层,我希望你的代码对吞吐量的影响相对较小。
最糟糕的是,在各种情况下为自己测试各种消息大小;很少有解决方案是一刀切的。
答案 1 :(得分:6)
不,没有通用的最佳字节大小。
TCP数据包会受到碎片的影响,虽然假设从这里到目的地的所有内容都是真正的以太网并且数据包大小很大,但实际上即使您可以获得所有单个网络的数据包大小也是如此。如果您的数据包占用,您发送的每个数据包都可能通过互联网采用不同的路径。
这不是你可以“解决”的问题,并且没有通用的理想尺寸。
尽可能快地将数据提供给操作系统和TCP / IP堆栈,它会动态调整数据包大小到网络连接(您应该看到他们用于此优化的代码 - 它真的非常有趣至少在更好的筹码上。)
如果您控制所使用的所有网络和堆栈,以及您的客户端/服务器之间,那么您可以进行一些手动调整。但一般来说,在我建议您接近之前,您必须非常好地掌握网络和发送的数据。
- 亚当
答案 2 :(得分:4)
如果您使用的是以太网TCP / IP,则最大数据包大小约为1500字节。如果您尝试一次发送多个数据,则数据将被分成多个数据包,然后再通过线路发送出去。如果应用程序中的数据已经打包,那么您可能希望选择一个小于1500的数据包大小,以便在发送完整数据包时,底层堆栈不必将其分解。例如,如果您执行的每个发送都是1600字节,则TCP堆栈必须为每个发送发送两个数据包,第二个数据包通常为空。这效率很低。
话虽如此,我不太了解这对性能的明显影响。
答案 3 :(得分:2)
我相信你的问题是你使用阻塞套接字而不是非阻塞套接字。
当您使用阻塞套接字并发送1M数据时,网络堆栈可以等待所有数据放入缓冲区,如果缓冲区已满,您将被阻止,进度条将等待整个要接受进入缓冲区的1M,这可能需要一段时间,而且您的进度条会很跳跃。
但是如果你使用非阻塞套接字,你使用的任何缓冲区大小都不会阻塞,你需要自己用select / poll / epoll / whatever-works-on-your-platform进行等待(选择是虽然最便携)。这样,您的进度条将快速更新并反映最准确的信息。
请注意,在发件人处,进度条会以任何方式部分中断,因为内核将缓冲某些数据,并且在对方确实收到数据之前您将达到100%。唯一的解决方法是,如果您的协议包含对接收方接收的数据量的回复。
正如其他人所说,第二次猜测操作系统和网络几乎是徒劳的,如果你继续使用阻塞套接字选择一个足够大的大小来包含比单个数据包更多的数据,这样你就不会发送太少的数据这样一个数据包会不必要地降低吞吐量。我会选择类似4K的东西,一次至少包含两个数据包。
答案 4 :(得分:1)
我要补充的一点是,对于给定的以太网连接,将小数据包作为大数据包发送需要花费很长时间。正如其他人所说:如果你只是发送一个数据流,让系统处理它。但是如果你担心来回的个别短消息,那么典型的以太网数据包大约需要1500字节 - 只要保持不变就应该是好的。
答案 5 :(得分:1)
您需要使用Path MTU Discovery,或使用良好的默认值(即小于1500字节)。
答案 6 :(得分:1)
创建一个名为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
num_terations在下载循环之外设置为0,并且在每个下载的块设置为numIterations + = 1之后
让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
答案 7 :(得分:0)
你可以做的一个经验测试,如果你还没有,当然是使用嗅探器(tcpdump,Wireshark等)并查看使用其他软件进行上传/下载时实现的数据包大小。这可能会给你一个提示。
答案 8 :(得分:0)
以下是您需要的公式:
int optimalChunkSize = totalDataSize / progressBar1.Width;
使用此功能,您发送的每个块都会将进度条增加1个像素。就用户反馈而言,较小的块大小毫无意义。