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

客户端连接断开后保持PiCamera对象持续活跃的实现方案

问题背景

在RPi4上使用picamera库开发视频流推流服务时,PiCamera官方文档提供的网络流录制基础服务端代码可正常运行,代码如下:

import socket
import time
import picamera

camera = picamera.PiCamera()
camera.resolution = (640, 480)
camera.framerate = 24

server_socket = socket.socket()
server_socket.bind(('0.0.0.0', 8000))
server_socket.listen(0)

# 接收单个连接并将其封装为类文件对象
connection = server_socket.accept()[0].makefile('wb')
try:
    camera.start_recording(connection, format='h264')
    camera.wait_recording(60)
    camera.stop_recording()
finally:
    connection.close()
    server_socket.close()

原生代码存在两个局限:仅接受单次客户端连接,固定录制60秒H264流后就会停止录制、关闭连接,无法满足长期运行需求。

针对需求做了两处修改:一是取消60秒录制时长限制,实现永久持续推流;二是调整逻辑让服务端socket永久监听端口,支持客户端反复接入。修改后的服务端代码如下:

import socket
import time
import picamera

camera = picamera.PiCamera()
camera.resolution = (640, 480)
camera.framerate = 30

server_socket = socket.socket()
server_socket.bind(('0.0.0.0', 8000))
server_socket.listen(0)

while True:  # 永久监听
    client_socket, client_address = server_socket.accept()
    print(f"New connection from {client_address}.")
    connection = client_socket.makefile('wb')
    try:
        camera.start_recording(connection, format='h264')
        while True:  # 持续推流不停止
            camera.wait_recording(1)
        camera.stop_recording()
    except BrokenPipeError as error:
        print(f"Error {error} occured.")
        # 调用camera.stop_recording()会触发ConnectionResetError,不调用则新连接接入时会报PiCameraAlreadyRecording
    finally:
        pass
    #    connection.close()
    #    server_socket.close()
故障现象

修改后的代码运行时出现异常:

  • 客户端主动断开连接会触发BrokenPipeError
  • 若在异常分支调用camera.stop_recording()方法,会触发ConnectionResetError报错
  • 若不调用该方法,后续新客户端连接接入时会触发PiCameraAlreadyRecording报错,无法完成重连推流

使用的客户端基于OpenCV开发,功能为拉取服务端H264流、垂直翻转画面、实时预览并存储为本地MP4文件,代码如下:

import numpy as np
import cv2
import sys
import datetime

server = 'http://192.168.178.54:8000/'
video_capture_0 = cv2.VideoCapture(server)
fourcc = cv2.VideoWriter_fourcc(*"mp4v")  # Ubuntu22.04下可用的编码:mp4v等
date_time_now = datetime.datetime.now()
yyyymmddHHMMSS = date_time_now.strftime("%Y-%m-%d_%H%M%S")
video_write_0 = cv2.VideoWriter(f"{yyyymmddHHMMSS}.mp4", fourcc, 30.0, (640, 480))  # 存储流到本地文件

while True:
    ret0, frame0 = video_capture_0.read()

    if ret0:
        frame0 = cv2.flip(frame0, 0)  # 垂直翻转画面
        cv2.imshow('Test 0', frame0)
        video_write_0.write(frame0)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

video_capture_0.release()
video_write_0.release()
cv2.destroyAllWindows()

需要实现的目标:客户端连接断开后PiCamera对象始终保持活跃状态,可正常响应后续新的客户端连接请求。

修复方案

问题根因

异常的核心原因是断连时的资源清理逻辑缺失:picamera启动录制后会持续向绑定的socket文件对象写入流数据,客户端断开后写入操作会触发IO异常,此时既没有安全重置相机的录制状态,也没有关闭失效的连接资源,导致相机一直被占用、新连接无法接入。

修复后服务端代码

import socket
import time
import picamera

# 全局仅初始化一次相机实例,避免反复启停硬件
camera = picamera.PiCamera()
camera.resolution = (640, 480)
camera.framerate = 30

server_socket = socket.socket()
# 开启端口复用,避免服务重启时端口被占用
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('0.0.0.0', 8000))
server_socket.listen(0)
print("Stream server started on port 8000")

while True:
    client_socket, client_address = server_socket.accept()
    print(f"New connection from {client_address}.")
    connection = client_socket.makefile('wb')
    try:
        camera.start_recording(connection, format='h264')
        # 持续推流,wait_recording会在连接异常时抛出错误
        while True:
            camera.wait_recording(1)
    except Exception as e:
        # 捕获所有断连相关的IO异常,包括BrokenPipeError、ConnectionResetError
        print(f"Client {client_address} disconnected: {str(e)}")
    finally:
        # 统一做资源清理,保证相机状态被重置
        try:
            if camera.recording:
                camera.stop_recording()
        except Exception as e:
            print(f"Stop recording warning: {str(e)}")
        # 关闭当前连接资源
        try:
            connection.close()
        except:
            pass
        try:
            client_socket.close()
        except:
            pass
    # 短暂停顿后回到监听状态,等待下一个客户端连接
    time.sleep(0.1)

关键修改点说明

  • 为服务端socket增加SO_REUSEADDR配置,解决服务重启时的端口占用问题
  • 扩大异常捕获范围,覆盖客户端断连时可能抛出的所有IO类错误,避免异常直接打断主监听循环
  • 资源清理逻辑统一放在finally块执行:先判断相机录制状态,安全调用stop_recording()并兜底捕获可能的异常,再依次关闭连接文件对象、客户端socket,保证每次连接结束后相机回到空闲状态
  • 服务端监听socket全程不关闭,相机实例全局只初始化一次,避免反复启停相机硬件带来的延迟和资源消耗
  • 每次断连清理完成后增加短暂时延,避免空转占用CPU资源

补充说明

当前客户端使用http://前缀拉取裸TCP H264流的方式,在网络波动时可能出现花屏、首帧加载慢的问题,如果后续需要更高的流稳定性,可以在推流端封装标准HTTP MJPG流或者部署轻量RTSP服务,当前代码已经可以满足断连后自动恢复、支持客户端反复接入的核心需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:01:47