Mar*_*ino 3 python sockets file
我正在尝试编写一个将二进制文件从客户端传输到服务器的程序。这是代码:
客户端(发送文件)
def send_file(self,filename):
print("Sending: " + filename)
size = self.BUFFER_SIZE
with open(filename,'rb') as f:
raw = f.read().decode()
buffer = [raw[i:i + size] for i in range(0, len(raw), size)]
for x in range(len(buffer)):
self.sock.sendall(buffer[x].encode())
return
Run Code Online (Sandbox Code Playgroud)
服务器(接收文件)
def recv_file(self, conn, filename):
packet = ""
buffer = ""
while True:
buffer = conn.recv(self.BUFFER_SIZE)
packet = packet + str(buffer.decode())
if not len(buffer) == self.BUFFER_SIZE:
break
with open(filename, 'wb') as f:
f.write(bytes(packet.encode()))
#print(packet)
return
Run Code Online (Sandbox Code Playgroud)
这样我可以传输 txt 文件,但是当我必须传输 jpeg 或任何其他类型的文件时,它会在循环中冻结。有人可以解释一下为什么吗?我是 py 新手,我正在努力学习
如果双方具有相同的区域设置编码,它不应该冻结,但它很容易因异常而死亡。
您正在以二进制形式读取和发送(好),但莫名其妙地decode-ing 到str,然后又encodeing 返回bytes(坏)。问题是,不能保证任意二进制数据在任何给定的语言环境中都是可解码的;如果您的区域设置编码是 UTF-8,那么它很可能是不合法的。如果是的话latin-1,这是合法的,但毫无意义。
更糟糕的是,如果您的客户端和服务器具有不同的区域设置编码,则双方的解码结果可能不同(因此长度不匹配)。
一致使用bytes,不要在字符串之间进行转换,区域设置也无关紧要。您的代码也会运行得更快。您还需要提前实际发送文件长度;您的循环希望recv仅在文件完成时返回较短的长度,但如果:
你们每个人都可以得到简短的recv结果,在情况 #2 中是巧合,在情况 #1 中是确定性的。
更安全的方法是在传输中实际添加文件长度前缀,而不是希望分块按预期工作:
def send_file(self,filename):
print("Sending:", filename)
with open(filename, 'rb') as f:
raw = f.read()
# Send actual length ahead of data, with fixed byteorder and size
self.sock.sendall(len(raw).to_bytes(8, 'big'))
# You have the whole thing in memory anyway; don't bother chunking
self.sock.sendall(raw)
def recv_file(self, conn, filename):
# Get the expected length (eight bytes long, always)
expected_size = b""
while len(expected_size) < 8:
more_size = conn.recv(8 - len(expected_size))
if not more_size:
raise Exception("Short file length received")
expected_size += more_size
# Convert to int, the expected file length
expected_size = int.from_bytes(expected_size, 'big')
# Until we've received the expected amount of data, keep receiving
packet = b"" # Use bytes, not str, to accumulate
while len(packet) < expected_size:
buffer = conn.recv(expected_size - len(packet))
if not buffer:
raise Exception("Incomplete file received")
packet += buffer
with open(filename, 'wb') as f:
f.write(packet)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4632 次 |
| 最近记录: |