屏幕日志项目截图传输异常:接收大小后仅获128KB,无大小可收全文件
问题分析与解决方案
核心问题1:客户端文件大小计算错误
你在客户端里用len(str(file))计算文件大小,这是错误的——str(file)会把字节对象转换成类似b'xxxx...'的字符串,这个字符串的长度和原始字节数据的长度完全无关。正确的做法是直接用len(file)获取字节数据的实际长度。
核心问题2:服务端未循环接收完整数据
TCP是流式协议,recv(size)不一定能一次性返回你请求的所有字节,它只会返回当前缓冲区里有的数据(默认缓冲区大小通常是128KB)。所以必须循环接收,直到累计拿到的字节数等于指定的大小。
修正后的客户端代码
import os from datetime import datetime import pygame import pyscreenshot as ImageGrab import socket def take_screenshot(): print("Taking screenshot...") image_name = f"screenshot-{str(datetime.now())}" image_name = image_name.replace(":", ";") screenshot = ImageGrab.grab(backend="mss", childprocess=False) filepath = f"./screenshots/{image_name}.png" screenshot.save(filepath) file = open(filepath, 'rb') b = file.read() file.close() os.remove(filepath) return b def main(): my_socket = socket.socket() my_socket.connect(("127.0.0.1", 8820)) clock = pygame.time.Clock() file = take_screenshot() # 修正:直接取字节数据的长度 file_size = len(file) print(file_size) # 发送固定10位的大小编码 + 原始字节数据 my_socket.send(str(file_size).zfill(10).encode() + file) my_socket.close() if __name__ == '__main__': main()
修正后的服务端代码
import os from datetime import datetime import MySQLdb as mysql import pygame import socket def server_setup(): S_socket = socket.socket() print("Server is up and running") return S_socket def client_bind(): global server_socket print("turning on server") server_socket.bind(("0.0.0.0", 8820)) server_socket.listen(1) (client_socket, client_address) = server_socket.accept() print(client_address[0]) return client_socket, client_address server_socket = server_setup() client_socket, client_address = client_bind() image_name = f"screenshot-{str(datetime.now())}" image_name = image_name.replace(":", ";") filepath = f"./screenshots/{image_name}.png" # 接收文件大小 size_data = client_socket.recv(10) size = int(size_data.decode()) print(f"Expected file size: {size}") # 循环接收完整数据 received_data = b'' while len(received_data) < size: # 每次接收剩余的字节数,或者缓冲区最大容量 chunk = client_socket.recv(min(size - len(received_data), 4096)) if not chunk: # 连接断开,提前结束 break received_data += chunk print(f"Received {len(received_data)} bytes") with open(filepath, 'xb') as new_file: new_file.write(received_data) client_socket.close() server_socket.close()
额外说明
- 服务端里的函数名
client_blind是笔误,已修正为client_bind。 - 循环接收时用
min(size - len(received_data), 4096)可以避免每次请求过大的缓冲区,同时保证高效接收剩余数据。 - 如果客户端意外断开,
recv会返回空字节串,这里加了判断可以提前终止接收,避免无限等待。
内容的提问来源于stack exchange,提问作者Matan F
相关产品推荐
相关产品推荐

