You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 19:53:07