RHEL 6.5下Erlang SSH_SFTP上传大文件报"Bad packet length"问题求助
解决Erlang/OTP 19 ssh_sftp上传大文件报"Bad packet length"的问题
我之前在使用OTP 19的ssh_sftp模块处理大文件上传时,也碰到过一模一样的问题。结合对这个版本OTP的了解,给你几个针对性的解决方案:
1. 调整SFTP数据包大小配置
OTP 19中ssh_sftp的默认数据包大小可能偏小,当上传超过1GB的文件时,拆分的数据包可能超出了协议允许的范围,导致服务器返回"Bad packet length"错误。你可以在建立SSH连接时手动指定更大的数据包大小:
% 建立SSH连接时添加sftp_packet_size参数,示例设置为1MB {ok, ConnRef} = ssh:connect("remote-host", 22, [ {user, "your-username"}, {password, "your-password"}, {sftp_packet_size, 1048576} % 1024*1024,可根据实际情况调整 ], 30000), % 获取SFTP进程ID {ok, SftpPid} = ssh_sftp:start_channel(ConnRef),
建议从1MB开始测试,逐步调整到服务器允许的最大值(一般不超过4MB),这个参数能有效避免单个数据包过大导致的协议错误。
2. 手动分块上传大文件
如果调整数据包大小后问题依然存在,可以尝试将大文件拆分成多个小分块,逐块上传。这种方式能彻底避免单次传输的数据包超过限制:
% 分块上传函数,ChunkSize建议设置为1MB upload_large_file(SftpPid, LocalPath, RemotePath) -> ChunkSize = 1048576, {ok, LocalFd} = file:open(LocalPath, [read, binary]), {ok, RemoteFd} = ssh_sftp:open(SftpPid, RemotePath, [write, binary]), case upload_chunk(LocalFd, RemoteFd, SftpPid, ChunkSize) of ok -> file:close(LocalFd), ssh_sftp:close(SftpPid, RemoteFd), ok; {error, Reason} -> file:close(LocalFd), ssh_sftp:close(SftpPid, RemoteFd), {error, Reason} end. upload_chunk(LocalFd, RemoteFd, SftpPid, ChunkSize) -> case file:read(LocalFd, ChunkSize) of {ok, Data} -> case ssh_sftp:write(SftpPid, RemoteFd, Data) of ok -> upload_chunk(LocalFd, RemoteFd, SftpPid, ChunkSize); Error -> Error end; eof -> ok; Error -> Error end.
这种方式通过把大文件拆分成多个小部分传输,完全规避了大数据包的问题,同时也能更好地监控上传进度。
3. 升级OTP版本(推荐)
OTP 19是2016年发布的版本,存在不少已知的SFTP模块bug,其中就包括大文件上传时的数据包处理问题。后续的OTP 21及以上版本对ssh_sftp模块进行了大量优化和修复,升级到较新的OTP版本(比如OTP 25或26)能从根源上解决这个问题。如果你的项目允许,这是最彻底的解决方案。
另外,虽然你排除了网络问题,但还是可以确认下本地SFTP服务器的配置(比如OpenSSH的MaxPacketSize参数),不过既然本地上传也报错,大概率还是客户端OTP版本或配置的问题。
内容的提问来源于stack exchange,提问作者Ankit Tripathi
相关产品推荐
相关产品推荐

