Socket传输Numpy数组异常:客户端发送摄像头帧0.1秒后停止
问题描述
我想要搭建一个Web服务器,实现单个连接用户的摄像头实时视频流传输。目前尝试通过Socket传输摄像头视频帧时遇到异常:客户端发送帧约0.1秒后便停止传输。
服务器输出
connection established with ('127.0.0.1', 63585) [[[138 157 155] [142 160 158] [145 161 157] ... [ 60 67 94] [ 57 64 90] [ 67 75 99]] [[144 160 159] [144 160 157] [145 160 156] ... [ 67 73 99] [ 63 70 94] [ 71 78 101]] [ 14 20 29] [ 13 21 28] ... [ 25 35 36] [ 23 33 34] [ 22 32 32]] [[ 15 19 28] [ 15 20 29] [ 15 21 28] ... [ 22 33 34] [ 22 33 33] [ 21 32 32]] [[ 16 19 28] [ 16 20 29] [ 16 21 29] ... [ 20 33 32] [ 20 33 32] [ 20 33 32]]]
代码文件
server.py
import cv2 import pickle import socket import struct TCP_IP = '127.0.0.1' TCP_PORT = 9501 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # establishing a tcp connection sock.bind((TCP_IP, TCP_PORT)) sock.listen(5) data = b'' payload_size = struct.calcsize("I") while True: client_socket, client_address = sock.accept() # wait for client print('connection established with ' ,client_address) while len(data) < payload_size: data += client_socket.recv(4096) packed_msg_size = data[:payload_size] data = data[payload_size:] msg_size = struct.unpack("I", packed_msg_size)[0] while len(data) < msg_size: data += client_socket.recv(4096) frame_data = data[:msg_size] data = data[msg_size:] if frame_data=='': break frame=pickle.loads(frame_data) print(frame) socket.close()
client.py
import cv2 import pickle import socket import struct TCP_IP = '127.0.0.1' TCP_PORT = 9501 server_address = (TCP_IP, TCP_PORT) streamer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) streamer.connect((TCP_IP,TCP_PORT)) while True: cap = cv2.VideoCapture(0) pos_frame = cap.get(cv2.CAP_PROP_POS_FRAMES) while True: flag, frame = cap.read() if flag: frame = pickle.dumps(frame) size = len(frame) p = struct.pack('I', size) frame = p + frame streamer.sendall(frame) else: cap.set(cv2.CAP_PROP_POS_FRAMES, pos_frame-1) if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT): size = 10 p = struct.pack("I", size) streamer.send(p) streamer.send('') break streamer.close()
问题分析与修复
核心问题点
- 客户端循环逻辑错误:外层
while True反复初始化摄像头,且错误判断帧计数触发终止,导致socket提前关闭。 - 服务器接收逻辑不完整:仅接收单帧后就停止处理,未持续接收后续帧。
- 字节流与字符串混用:
streamer.send('')发送字符串而非字节流,违反socket传输规则。
修复后的代码
修复后的client.py
import cv2 import pickle import socket import struct TCP_IP = '127.0.0.1' TCP_PORT = 9501 # 仅初始化一次摄像头 cap = cv2.VideoCapture(0) if not cap.isOpened(): print("无法打开摄像头") exit() # 建立socket连接 streamer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: streamer.connect((TCP_IP, TCP_PORT)) except ConnectionRefusedError: print("无法连接到服务器") cap.release() exit() try: while True: flag, frame = cap.read() if not flag: print("读取帧失败") continue # 序列化帧并发送 frame_data = pickle.dumps(frame) size = struct.pack('I', len(frame_data)) streamer.sendall(size + frame_data) # 按q键退出传输 if cv2.waitKey(1) & 0xFF == ord('q'): break finally: # 释放所有资源 cap.release() streamer.close() cv2.destroyAllWindows()
修复后的server.py
import cv2 import pickle import socket import struct TCP_IP = '127.0.0.1' TCP_PORT = 9501 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((TCP_IP, TCP_PORT)) sock.listen(5) print(f"服务器监听在 {TCP_IP}:{TCP_PORT}") while True: client_socket, client_address = sock.accept() print(f"与 {client_address} 建立连接") data = b'' payload_size = struct.calcsize("I") try: while True: # 接收帧大小 while len(data) < payload_size: chunk = client_socket.recv(4096) if not chunk: # 客户端断开连接 raise ConnectionResetError data += chunk packed_msg_size = data[:payload_size] data = data[payload_size:] msg_size = struct.unpack("I", packed_msg_size)[0] # 接收完整帧数据 while len(data) < msg_size: chunk = client_socket.recv(4096) if not chunk: raise ConnectionResetError data += chunk frame_data = data[:msg_size] data = data[msg_size:] # 反序列化并显示帧 frame = pickle.loads(frame_data) cv2.imshow('摄像头实时流', frame) # 按q键关闭窗口,等待新连接 if cv2.waitKey(1) & 0xFF == ord('q'): cv2.destroyAllWindows() break except (ConnectionResetError, BrokenPipeError): print(f"{client_address} 断开连接") finally: client_socket.close() sock.close()
内容的提问来源于stack exchange,提问作者malcom32
相关产品推荐
相关产品推荐

