当客户端断开连接时,如何在 django 中停止 StreamingHttpResponse?

Posted

技术标签:

【中文标题】当客户端断开连接时,如何在 django 中停止 StreamingHttpResponse?【英文标题】:How do you stop a StreamingHttpResponse in django when the client disconnects? 【发布时间】:2019-07-13 13:05:50 【问题描述】:

我的 django 服务器提供视频源,作为 jpeg 流,一次一帧。

看起来像这样:

class VideoCamera():
    def __init__(self):
        # code

    def get_frame(self):
        # code
        return frame

def gen(camera):
    while True:
        yield camera.get_frame()

def view_cam(request):
    return StreamingHttpResponse(gen(VideoCamera()), content_type="multipart/x-mixed-replace;boundary=frame")

这是一个实时摄像头,所以没有尽头。我需要在客户端断开连接时将其中断,但到目前为止,我无法弄清楚如何检测客户端断开连接。

我错过了什么吗?

编辑:

为了消除与相机有关的任何事情,我这样做了:

def gen():
    for i in range(1000):
        time.sleep(1)
        print(i)
        yield i

def view_cam(request):
    return StreamingHttpResponse(gen(), content_type="multipart/x-mixed-replace;boundary=frame")

并通过curl -N http://localhost/my_app/view_cam/ 连接到我的视图。它流式传输数字,当我用 Ctrl+C 停止 curl 时,生成器只是无限期地运行,没有注意到客户端消失了。如果我再运行和停止 curl 几次,我的 gen() 函数的多个实例正在运行,这正是相机发生的情况。

编辑 2:

这个项目使用 Django 频道。我只是注意到,如果我通过在我的 settings.py 中注释掉频道来禁用频道,上面的示例就可以完美运行。我不认为渠道与问题有关,但显然,它是 - 不知何故。

频道开发服务器确实在 10 秒后检测到断开连接(不像默认的 django 服务器那样立即),并显示如下:

应用程序实例 call() 运行在 /home/pi/paperless_clipboard/venv3/lib/python3.5/site-packages/channels/http.py:213> wait_for=._call_check_cancel() 在 /usr/lib/python3.5/asyncio/futures.py:452,Task._wakeup()]>> for 连接需要很长时间才能关闭并被终止。

但是尽管有消息说有东西被杀了,gen() 继续运行,将数字打印到终端。

【问题讨论】:

在将 StreamingHttpResponse 与 django 频道一起使用时,我似乎在生产中遇到了问题。我看到一个失控的进程消耗了大量的 CPU,它处理的最后一个请求是通过 django 通道向客户端返回 StreamingHttpResponse。你有没有让 StreamingHttpResponse 与 django 频道一起工作?还是只是认为这是罪魁祸首并禁用了 django 频道? 我已经有一段时间没有做这个了,但如果我记得,我从来没有解决过这个问题。我想我只是通过使用通道 websocket 返回相机帧而不是 StreamingHttpResponse() 来解决它 嗨@John,你能分享一个你如何使用opencv而不是StreamingHttpResponse()返回帧的示例吗? 【参考方案1】:

你不能根据文档:

性能考虑 Django 专为短期请求而设计。流式响应将在整个响应期间绑定一个工作进程。这可能会导致性能不佳。

一般来说,您应该在请求-响应周期之外执行昂贵的任务,而不是诉诸流式响应。

https://docs.djangoproject.com/en/2.1/ref/request-response/#streaminghttpresponse-objects

【讨论】:

在不启用django channels 的情况下似乎可以正常工作。 Streaming 响应被中断,类的__del__ 方法开始运行,这正是我所希望的。我只是不确定为什么它不适用于启用channels

以上是关于当客户端断开连接时,如何在 django 中停止 StreamingHttpResponse?的主要内容,如果未能解决你的问题,请参考以下文章

django 频道如何知道客户端已断开连接?

如果客户端断开连接,则停止执行 PHP 脚本

当客户端更改 IP 地址或断开连接时,如何捕捉 websocket-close 事件?

点燃缓存重新连接问题(缓存已停止)

在播放框架中发送大文件时如何捕获客户端断开连接?

如何从客户端断开和重新连接 socket.io?