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

Python Socket文件传输仅PDF文件失效问题求助

问题:PDF文件传输失败,服务端生成0KB空文件

开发了一套支持CSV和PDF文件传输、具备哈希完整性校验的Socket客户端与服务端程序,CSV文件传输完全正常,但传输PDF文件时,服务端仅生成一个仅含文件名的0KB空文件,recv()始终读取为空。

客户端putFile函数代码

def putFile(filename, serverIP, port, BUFFER_SIZE,s): #sends file to a server
filesize= os.path.getsize(filename)

#make and send hash
hexhash=getHash(filename)#make hash
s.send(hexhash.encode())#send hash 
print("Hash sent",hexhash)
received=s.recv(BUFFER_SIZE).decode()#receive response from server 
print(received)#print response

#send file
s.send(f"{filename}[SEPARATOR]{filesize}".encode())#send file name and size

with open(filename, "rb") as f: #open as read in binary to read in chunks
    while True:
       
        bytes_read = f.read(BUFFER_SIZE)#.encode() # read the bytes from the file in 4096B
        if not bytes_read:  # file transmitting is done
            print("Sent")
            #s.sendall(bytes_read)
            #s.send(("").encode())
            break
        s.sendall(bytes_read) #sendall assures transimission in busy networks 
        print(bytes_read)

print("waiting")
received=s.recv(BUFFER_SIZE).decode()#receive response from server about hash
print(received)#print response
if received== "Good hash":
    print("File stored")
elif received=="Bad Hash":
    print("File sent does not match file received")
    
s.close()
return 

服务端storeFile函数代码

storeFile(fileheader, cli, hexhash): #eceives a file from a client

filename, filedata=fileheader.split("[SEPARATOR]")

filename=os.path.basename(filename)#just the file name
print("File:",filename)   
#filesize=int(filesize)
cli.setblocking(False)   
with open(filename, "wb") as f: #save file
    while True:
        print("loop")
        try:
            print("trying")
            bytes_read = cli.recv(BUFFER_SIZE)# read up to BUFFSIZE bytes from the client
            print("reading:",bytes_read)
        except socket.error as e:
            print("except")
            err = e.args[0]
            if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
                sleep(1)
                print("File Saved")
                break
            else:
                # a "real" error occurred
                print(e)
                sys.exit(1)
        else:
            # got a message, do something :)
            print("write")
            f.write(bytes_read)  # write to the file the bytes we just received)

       
#cli.close()
cli.setblocking(True)
#receive hash
check=checkHash(hexhash,filename)#check the hash given and the file hash, hash and file are given
if check: #hashes match
    cli.send(("Good hash").encode())#respond to clent that hashes match
    #print(received.split(SEPARATOR))
    
    #s.close()
    #END FILE RECEIPT"""
elif not check:
    cli.send("Bad hash".encode())
#cli.close()
return

问题分析与修复方案

核心问题

  1. 非阻塞模式误用:服务端设置了非阻塞cli.setblocking(False),但没有根据文件大小判断接收是否完成,一遇到EAGAIN/EWOULDBLOCK(无数据可读)就直接终止接收循环。CSV文件体积小,数据可能在设置非阻塞前就已到达缓冲区,所以能正常接收;但PDF文件体积大,客户端还没传输完数据,服务端就触发无数据异常退出循环,导致生成空文件。
  2. 未利用文件大小控制接收:服务端从fileheader中解析出了filedata(即文件大小),但没有转为整数并累计接收字节数,完全依赖非阻塞异常终止接收,逻辑错误。

修复步骤

1. 移除非阻塞模式,改用基于文件大小的循环接收

服务端不需要设置非阻塞,直接按阻塞模式接收,直到累计接收字节数达到文件大小。

2. 修正文件大小解析与接收逻辑

将filedata转为整数类型的filesize,循环中累计接收字节数,达到filesize后停止接收。

修改后的服务端storeFile函数代码

def storeFile(fileheader, cli, hexhash): #receives a file from a client
    filename, filedata = fileheader.split("[SEPARATOR]")
    filename = os.path.basename(filename)
    filesize = int(filedata)  # 解析文件大小
    print("File:", filename, "Size:", filesize)   

    received_bytes = 0
    with open(filename, "wb") as f:
        while received_bytes < filesize:
            bytes_read = cli.recv(BUFFER_SIZE)
            if not bytes_read:
                # 连接异常中断
                print("Connection lost during file transfer")
                os.remove(filename)  # 删除不完整文件
                return
            f.write(bytes_read)
            received_bytes += len(bytes_read)
            print(f"Received {received_bytes}/{filesize} bytes")

    # 哈希校验
    check = checkHash(hexhash, filename)
    if check:
        cli.send("Good hash".encode())
        print("File stored successfully")
    else:
        cli.send("Bad hash".encode())
        os.remove(filename)  # 删除校验失败的文件
    return

3. 额外注意点

  • 确保客户端与服务端的BUFFER_SIZE定义一致,避免解析错误。
  • 哈希校验前要确保文件完全写入磁盘,当前代码中with语句会自动关闭文件,无需额外处理。

内容的提问来源于stack exchange,提问作者Justin Manne

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 10:25:22