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
问题分析与修复方案
核心问题
- 非阻塞模式误用:服务端设置了非阻塞
cli.setblocking(False),但没有根据文件大小判断接收是否完成,一遇到EAGAIN/EWOULDBLOCK(无数据可读)就直接终止接收循环。CSV文件体积小,数据可能在设置非阻塞前就已到达缓冲区,所以能正常接收;但PDF文件体积大,客户端还没传输完数据,服务端就触发无数据异常退出循环,导致生成空文件。 - 未利用文件大小控制接收:服务端从
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
相关产品推荐
相关产品推荐

