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

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()

问题分析与修复

核心问题点

  1. 客户端循环逻辑错误:外层while True反复初始化摄像头,且错误判断帧计数触发终止,导致socket提前关闭。
  2. 服务器接收逻辑不完整:仅接收单帧后就停止处理,未持续接收后续帧。
  3. 字节流与字符串混用: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:30:48