Python socket.recv跨平台传输数据大量缺失问题求助
Socket文件传输不完整问题排查
尝试将220700字节的文件从Linux主机发送到Windows笔记本,Linux端显示已发送全部字节,但Windows端仅能接收55000-80000字节左右的随机数据量,相关代码如下:
Linux端发送代码
import socket import os csi_file_path = "your_file_path" # 替换为实际文件路径 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(("0.0.0.0", 65432)) while True: s.listen() conn, addr = s.accept() with conn: conn.sendall(os.path.getsize(csi_file_path).to_bytes(8, 'big')) sent_bytes = conn.sendfile(open(csi_file_path, "r+b")) print(f"Sent {sent_bytes} bytes") conn.shutdown(socket.SHUT_RDWR)
Windows端接收代码
import socket con_details = {"HOST": "linux_host_ip", "PORT": 65432} # 替换为实际主机IP def receive_byte_array(sckt, expected_size=0): response = bytearray() while len(response) < expected_size: chunk = sckt.recv(expected_size - len(response)) if len(chunk) == 0: break print(f"Received chunk of size {len(chunk)}") response.extend(chunk) return response with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((con_details.get("HOST"), con_details.get("PORT"))) s.settimeout(20.0) incoming_length = int.from_bytes(receive_byte_array(s, 8), "big") cir_data = receive_byte_array(s, incoming_length)
可能的原因及解决方案
1. sendfile未完整发送数据
Linux的sendfile调用可能不会一次性发送全部文件内容,返回的sent_bytes仅代表当前已调度发送的字节数,而非实际已传输到对端的字节数。若文件较大或网络缓冲区有限,需要循环调用sendfile直到发送完所有数据。
修改后的发送逻辑:
file_size = os.path.getsize(csi_file_path) with open(csi_file_path, "rb") as f: sent_total = 0 while sent_total < file_size: sent = conn.sendfile(f, offset=sent_total) if sent == 0: break sent_total += sent print(f"Sent {sent_total} bytes")
2. 连接过早关闭
Linux端在sendfile后立即调用conn.shutdown(socket.SHUT_RDWR),会直接关闭连接的读写方向,此时socket缓冲区中未发送的数据可能被丢弃,导致Windows端提前收到EOF,终止接收。
优化方案:
- 先关闭写方向(
SHUT_WR),告知对端发送已完成,再等待对端确认后关闭连接:
# 发送完文件后 conn.shutdown(socket.SHUT_WR) # 等待对端的确认信号(比如接收一个字节的响应) try: conn.recv(1) except Exception: pass
- 或者移除
shutdown调用,依赖with conn:上下文在代码块结束时自动关闭连接(此时会等待缓冲区数据发送完成)。
3. 文件打开模式问题
Linux端使用"r+b"模式打开文件,虽然二进制读写模式本身无错,但sendfile更适配只读二进制模式"rb",建议修改打开模式避免潜在问题。
4. 接收端EOF处理逻辑缺陷
Windows端接收函数在recv返回空(EOF)时直接终止循环,若连接提前关闭,会导致未接收完数据就停止。可以添加异常抛出,明确中断原因:
def receive_byte_array(sckt, expected_size=0): response = bytearray() while len(response) < expected_size: chunk = sckt.recv(expected_size - len(response)) if len(chunk) == 0: raise RuntimeError(f"连接提前关闭,已接收{len(response)}字节,预期{expected_size}字节") print(f"Received chunk of size {len(chunk)}") response.extend(chunk) return response
内容的提问来源于stack exchange,提问作者binaryBigInt
相关产品推荐
相关产品推荐

