我实际上是使用Python的ftplib(2.7版本)将文件发送到FTP服务器,但在底层它使用socket.sendall。下面是相关函数:
def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
"""Store a file in binary mode. A new port is created for you.
Args:
cmd: A STOR command.
fp: A file-like object with a read(num_bytes) method.
blocksize: The maximum data size to read from fp and send over
the connection at once. [default: 8192]
callback: An optional single parameter callable that is called on
on each block of data after it is sent. [default: None]
rest: Passed to transfercmd(). [default: None]
Returns:
The response code.
"""
self.voidcmd('TYPE I')
conn = self.transfercmd(cmd, rest)
while 1:
buf = fp.read(blocksize)
if not buf: break
conn.sendall(buf)
if callback: callback(buf)
conn.close()
return self.voidresp()
我正在尝试选择最优的块大小,或者至少了解影响它的因素。代码目前在本地千兆网络上运行,在FTP服务器上ping时间为0.2ms(是的,0.2ms,而不是0.2s),使用Ubuntu内核3.2。我对TCP窗口缩放和发送/接收/拥塞窗口有相当的理解。我正在通过这个网络发送2GB的文件,并且实践中发现,随着块大小的增加,传输速度增加,使用256KB块大小可达到533Mb/s。参考一下,64KB的块大小大约为330Mb/s。
我并不是抱怨这些速度,但我想知道为什么256KB的块大小是最优的。到目前为止,我发现的所有信息都表明,大约需要64KB的块大小。我已经计时存储二进制函数的子组件,以确保发送文件的总时间实际上随着块大小的增加而减少,而不是花费在读取文件上的时间。
我的传输这些2GB文件的代码最终将在许多网络上运行(虽然是相同的操作系统、内核和Python版本)。我担心256KB在其他网络上是次优的,我很好奇为什么256KB的块大小可以提供最快的传输速度。任何见解都将不胜感激。
编辑:对于那些担心我如何计时实际的socket.sendall调用的人,这里是我用来计时的函数的修改版本。从64KB块到256KB块,读取时间从约19秒减少到约14秒,发送时间从约18秒减少到约10秒。
def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
"""Store a file in binary mode. A new port is created for you.
Args:
cmd: A STOR command.
fp: A file-like object with a read(num_bytes) method.
blocksize: The maximum data size to read from fp and send over
the connection at once. [default: 8192]
callback: An optional single parameter callable that is called on
on each block of data after it is sent. [default: None]
rest: Passed to transfercmd(). [default: None]
Returns:
The response code.
"""
self.voidcmd('TYPE I')
conn = self.transfercmd(cmd, rest)
totalTime = 0
totalSendTime = 0
totalCallbackTime = 0
while 1:
startTime = time.time()
buf = fp.read(blocksize)
endTime = time.time()
if not buf: break
totalTime += (endTime - startTime)
startTime = time.time()
conn.sendall(buf)
endTime = time.time()
totalSendTime += (endTime - startTime)
startTime = time.time()
if callback: callback(buf)
endTime = time.time()
totalCallbackTime += (endTime - startTime)
print 'Total read time was %s'%str(totalTime)
print 'Total send time was %s'%str(totalSendTime)
print 'Total callback time was %s'%str(totalCallbackTime)
conn.close()
return self.voidresp()