如何在Ruby中通过Socket传输文件?解决无限循环问题
解决Socket文件传输后脚本无限循环的问题
你的三次尝试都存在核心问题:TCP连接未在服务器端主动关闭,或者长度传输逻辑错误,导致客户端的read操作一直阻塞等待数据,无法终止循环。下面逐个分析错误原因,并给出修复方案:
错误原因分析
第一次尝试
服务器写完文件内容后,没有关闭与客户端的连接。TCP是流式协议,客户端的socket.read(1024)会一直尝试从连接中读取数据,只要连接未关闭,就不会返回nil,因此陷入无限循环。
第二次尝试
client.write nil无效,Socket传输的是字节流,无法写入nil值。同时服务器端依然没有关闭连接,客户端的read操作还是会持续阻塞。
第三次尝试
- 直接写入
content.length是将数字转为字符串传输,但客户端用gets读取,gets会一直等待换行符,而服务器端没有写入换行,导致socket.gets永久阻塞。 - 即使侥幸读到长度,如果文件内容中包含换行符,
gets会提前截断,导致读取的长度错误,后续socket.read(length)也会出现问题。
修复方案
方案一:传输完成后主动关闭服务器端Socket
写完文件内容后立即关闭客户端连接,让客户端的read操作返回nil,终止循环:
require 'socket' server = TCPServer.new 5555 Thread.new do client = server.accept File.open('files.zip', 'rb') do |file| while chunk = file.read(1024) client.write(chunk) end end client.close # 关键:传输完成后关闭连接 end socket = TCPSocket.new('localhost', 5555) File.open('files_backup.zip', 'wb') do |file| while chunk = socket.read(1024) file.write(chunk) end end socket.close
方案二:先传输文件长度(二进制格式)
用二进制打包的方式传输文件长度,避免字符串分隔符的问题,读完指定长度后主动终止操作:
require 'socket' server = TCPServer.new 5555 Thread.new do client = server.accept content = File.binread('hackers.zip') # 用8字节无符号整数打包文件长度(跨平台兼容) client.write([content.length].pack('Q')) client.write(content) client.close end socket = TCPSocket.new('localhost', 5555) File.open('hackers_backup.zip', 'wb') do |file| # 读取8字节的长度数据 length_bytes = socket.read(8) length = length_bytes.unpack('Q')[0] # 读取指定长度的文件内容 content = socket.read(length) file.write(content) end socket.close
这两种方案都能解决无限循环的问题:第一种通过关闭连接让客户端感知传输结束;第二种通过预先约定的长度,让客户端读取到指定字节后即可终止操作。
内容的提问来源于stack exchange,提问作者user14527579
相关产品推荐
相关产品推荐

