Python 的 ftplib 损坏发送的文件 - Winsock 问题?
Python's ftplib corrupting sent files - Winsock issue?
我们有一个 Python 应用程序,用于在 PC 上的 SVN 签出和 IBM i 中端系统之间来回传输源文件。
它已经使用了很多年,没有任何问题。
最近,我们开始看到源文件在从 PC 发送到 IBM i 时被损坏。目的地的线路乱序。 Wireshark 表明数据正在离开 PC。
有时很好用,有时是一两行乱,有时是很多行。
在出现此问题之前脚本没有更改。
这是 Python 代码中的 storlines()
调用:
connection.storlines('STOR ' + ibmi_file, open(source_file.fullpath, 'rb'))
最初,我在 Windows 10 上使用 Python 2.7.12。我尝试升级到 2.7.13,但我仍然看到问题。我尝试移动到 3.6.1,但我仍然看到问题。
其他开发人员也看到了这个问题,运行 Python 和 Windows 的各种版本。
我下载了 3.6.1 源代码并在 socketmodule.c
中的 sock_sendall() 和 sock_send_impl() 添加了一些调试日志记录
我可以看到从 sock_send_impl() 发送了以下内容。
来源
line# - 长度(字节)
1 - 79
2 - 73
3 - 38
4 - 73
5 - 78
6 - 41
Wireshark 显示以下 FTP 个数据包。
数据包# - FTP数据长度
1 - 79
2 - 1452
问题是数据包 2 以源代码行开始:
2、5、3、4
据我了解,sock_send_impl() 是将数据传递给 OS 的地方。我意识到 Nagle's algorithm 用于将小发送组合成一个较大的 TCP 数据包。
但是该数据包中的数据应该与传递给发送的顺序相同。而事实并非如此。
我认为这可能与最近的一些 Windows 补丁有关,只是我们的一位开发人员使用 Mac 遇到了同样的(?)问题。
我们确实有一位开发人员 运行 Windows 7 至少报告没有看到这个问题(他已经出去了)。
这对我来说没有任何意义,我不知道从这里到哪里去。
我们有理由确定问题是由 Symantec Vontu 14.6 MP1 版引起的;这是一种数据丢失防护 (DLP) 产品,"inspects" 在离开 PC 之前对其进行打包。
我相信该问题已报告给 Symantec。
与此同时,我们通过扩展基础 ftplib.FTP
class 并添加新函数解决了这个问题:
#stortext combines block read from STORBINARY with ASCII transfer mode from STORLINE
def stortext(self, cmd, fp, blocksize=8192, callback=None, rest=None):
self.voidcmd('TYPE A')
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()
我们不再遇到乱码问题。作为奖励,传输 运行 比 storline
.
快得多
所以我们继续使用我们的新功能。
我们有一个 Python 应用程序,用于在 PC 上的 SVN 签出和 IBM i 中端系统之间来回传输源文件。
它已经使用了很多年,没有任何问题。
最近,我们开始看到源文件在从 PC 发送到 IBM i 时被损坏。目的地的线路乱序。 Wireshark 表明数据正在离开 PC。
有时很好用,有时是一两行乱,有时是很多行。
在出现此问题之前脚本没有更改。
这是 Python 代码中的 storlines()
调用:
connection.storlines('STOR ' + ibmi_file, open(source_file.fullpath, 'rb'))
最初,我在 Windows 10 上使用 Python 2.7.12。我尝试升级到 2.7.13,但我仍然看到问题。我尝试移动到 3.6.1,但我仍然看到问题。
其他开发人员也看到了这个问题,运行 Python 和 Windows 的各种版本。
我下载了 3.6.1 源代码并在 socketmodule.c
中的 sock_sendall() 和 sock_send_impl() 添加了一些调试日志记录我可以看到从 sock_send_impl() 发送了以下内容。
来源
line# - 长度(字节)
1 - 79
2 - 73
3 - 38
4 - 73
5 - 78
6 - 41
Wireshark 显示以下 FTP 个数据包。
数据包# - FTP数据长度
1 - 79
2 - 1452
问题是数据包 2 以源代码行开始:
2、5、3、4
据我了解,sock_send_impl() 是将数据传递给 OS 的地方。我意识到 Nagle's algorithm 用于将小发送组合成一个较大的 TCP 数据包。
但是该数据包中的数据应该与传递给发送的顺序相同。而事实并非如此。
我认为这可能与最近的一些 Windows 补丁有关,只是我们的一位开发人员使用 Mac 遇到了同样的(?)问题。
我们确实有一位开发人员 运行 Windows 7 至少报告没有看到这个问题(他已经出去了)。
这对我来说没有任何意义,我不知道从这里到哪里去。
我们有理由确定问题是由 Symantec Vontu 14.6 MP1 版引起的;这是一种数据丢失防护 (DLP) 产品,"inspects" 在离开 PC 之前对其进行打包。
我相信该问题已报告给 Symantec。
与此同时,我们通过扩展基础 ftplib.FTP
class 并添加新函数解决了这个问题:
#stortext combines block read from STORBINARY with ASCII transfer mode from STORLINE
def stortext(self, cmd, fp, blocksize=8192, callback=None, rest=None):
self.voidcmd('TYPE A')
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()
我们不再遇到乱码问题。作为奖励,传输 运行 比 storline
.
所以我们继续使用我们的新功能。