基于Django websocket实现视频画面的实时传输功能(最新推荐)
作者:cyl-2002
基于Django websocket实现视频画面的实时传输案例
📌本案例是基于B/S架构的视频监控画面的实时传输,使用django作为服务端的开发框架。
Django Channels 是一个用于在 Django 框架中实现实时、异步通信的扩展库。传统的 Django 是基于请求-响应模式的,每个请求都会经过 Django 的视图函数进行处理并返回响应。而 Channels 提供了基于事件驱动的编程模型,使得开发者可以处理实时的事件,如 WebSocket 连接、消息队列、定时任务等。
Channels 的主要特性包括:
- 支持 WebSocket:Channels 可以轻松地处理 WebSocket 连接,实现实时的双向通信;
- 异步处理:Channels 使用异步方式处理请求和事件,可以提高应用的性能和并发能力;
- Channels 可以与诸如 Celery 等任务队列库集成,处理后台任务和定时任务。
Channels可以跟Django无缝衔接,常用于开发聊天室、实时通知、实时数据更新等。
WebSocket 是一种在客户端和服务器之间进行双向通信的网络协议。与传统的 HTTP 请求-响应模式不同,WebSocket 只需要完成一次握手就可以创建持久性的连接,允许服务器主动向客户端推送数据,而不需要客户端发起请求。
在使用 WebSocket 进行通信时,涉及到异步和同步两个概念:
在异步模式下,websocket使用异步的方式操作i/o,允许同时处理多个连接或事件。
在同步模式下,每个 WebSocket 连接会被分配给一个线程或进程进行处理,消息的接收和发送是同步的操作。同步方式适用于一对一的连接事件。
环境配置
1、下载安装channels库
pip install channels
2、添加 Channels 到 Django 项目的安装应用列表中:打开 Django 项目的 settings.py
文件,在 INSTALLED_APPS
设置中添加 'channels'
,确保它出现在其他应用的前面:
INSTALLED_APPS = [ ... 'channels', ... ]
并且在settings.py
文件添加以下内容:
ASGI_APPLICATION = "projetc2.asgi.application" #project2为项目名称 CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels.layers.InMemoryChannelLayer', }, }
Django Channels 运行于 ASGI(Asynchronous Server Gateway Interface)协议上。ASGI 是一个用于处理异步 Python Web 应用程序的协议,它提供了一种标准的方式来与 Web 服务器和应用程序框架之间进行通信。
3、配置 Channels 的 ASGI 应用程序:在 Django 项目的根目录下有一个名为 asgi.py
的文件,然后将文件中修改为以下内容:
import os from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application from projetc2 import routing os.environ.setdefault('DJANGO_SETTINGS_MODULE', '项目名称.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": URLRouter(routing.websocket_urlpatterns) })
4、配置 WebSocket 路由:在 Django 项目 project
的目录下创建一个名为 routing.py
的文件,然后定义您的 WebSocket 路由。以下是一个示例:
from django.urls import re_path from app import consumers websocket_urlpatterns = [ re_path(r'ws/some-path1/$', consumers.TailfConsumer.as_asgi()), ]
5、创建 WebSocket 消费者:在 myapp
应用的目录下创建一个名为 consumers.py
的文件,定义您的 WebSocket 消费者类。
使用 Django WebSocket 实现循环发送图像数据
当使用 Django WebSocket 实现循环发送数据时,可能会遇到 “took too long to shut down and was killed” 错误。这个错误通常是因为循环发送数据的操作没有正确终止导致的。
AsyncWebsocketConsumer
是 Django Channels 中用于处理 WebSocket 连接的异步消费者类。它是一个基于协程的类,用于处理 WebSocket 连接的生命周期、接收和发送消息等操作。
创建一个继承AsyncWebsocketConsumer
的自定义消费者类
class TailfConsumer(AsyncWebsocketConsumer): async def connect(self): """ 这里定义连接建立时的逻辑 """ # 接受客户端连接 await self.accept() # 开启循环发送数据 asyncio.ensure_future(self.send_data_loop()) async def disconnect(self, close_code): # 连接断开时的逻辑 pass async def send_data_loop(self): while True: # 获取数据 data = await self.get_data() await self.send(json.dumps(data)) await asyncio.sleep(1) # 假设每秒发送一次数据 async def get_data(self): """ 监听端口5000 ,实时获取视频图像数据 """ import pickle import socket # 创建客户端 socket 对象 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置服务器地址和端口号 server_address = ('192.168.1.106', 5000) # 连接服务器 client_socket.connect(server_address) decoded_data = {"leftimg":""} try: # 接收数据 received_data = client_socket.recv(600000000) # 如果接收到数据,则进行处理 if received_data: try: decoded_data = pickle.loads(received_data) # 在这里处理解码后的数据 except pickle.UnpicklingError as e: # 处理解码错误 print(f"Failed to decode pickle data: {e}") client_socket.close() except Exception as e: print('接收数据时出错:', str(e)) return decoded_data
async
和 await
是 Python 中用于定义和处理异步操作的关键字。它们与协程(coroutine)一起使用,以实现更高效的并发和非阻塞的编程。
创建一个脚本打开摄像头模拟通过socket发送图像数据,由于直接打开摄像头不能被多个用户同时获取数据,所以采用这种方式实时发送数据,脚本如下:
import pickle import socket import threading import cv2 import base64 video_source = 0 # 创建视频捕获对象 cap = cv2.VideoCapture(video_source) # 获取视频的宽度和高度 width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 用于存储连接的客户端 Socket client_sockets = [] import random # 生成一个包含19个随机整数的列表 # 创建 socket 对象 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定服务器地址和端口 server_address = ('192.168.1.106', 5000) server_socket.bind(server_address) # 监听客户端连接 server_socket.listen(1) def image_to_base64(image): # 将图像数据编码为 Base64 字符串 image_base64 = base64.b64encode(image).decode('utf-8') return image_base64 # 定义发送视频数据的函数 def send_video_data(): while True: ret, frame = cap.read() if not ret: break # 将图像编码为 JPEG 格式 _, image_data = cv2.imencode('.jpg', frame) # 遍历所有客户端连接,发送视频数据 for client_socket in client_sockets: try: # 发送图像数据 encoded_data = pickle.dumps({ "leftimg": image_to_base64(image_data), }) client_socket.sendall(encoded_data) except Exception as e: print(f"Error sending video data to client: {e}") client_socket.close() client_sockets.remove(client_socket) # 定义处理客户端连接的函数 def handle_client_connection(client_socket): while True: try: # 接收客户端请求 data = client_socket.recv(1024) if not data: break # 处理客户端请求 # 在此可以添加其他自定义逻辑 except Exception as e: print(f"Error handling client connection: {e}") break # 关闭客户端连接 client_socket.close() client_sockets.remove(client_socket) # 接受客户端连接,并启动视频发送线程 def accept_client_connections(): while True: client_socket, _ = server_socket.accept() client_sockets.append(client_socket) # 启动视频发送线程和客户端连接接受线程 send_thread = threading.Thread(target=send_video_data) accept_thread = threading.Thread(target=accept_client_connections) send_thread.start() accept_thread.start()
前端代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <img width="800" height="500" id="image"> <script> var socket = new WebSocket("ws://192.168.1.106:8000/ws/some-path1/"); socket.onopen = function(event) { console.log("WebSocket连接已打开"); }; socket.onmessage = function(event) { // 接收到消息时的处理 const imageData = event.data; // 从事件中获取图像数据 // 在前端显示图像数据,这里假设有一个img元素来显示图像 const imgElement = document.getElementById('image'); imgElement.src = "data:image/jpeg;base64," + JSON.parse(imageData)["leftimg"]; }; socket.onclose = function(event) { console.log("WebSocket连接已关闭"); }; </script> </body> </html>
到此这篇关于基于Django websocket实现视频画面的实时传输案例的文章就介绍到这了,更多相关Django websocket实时传输内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!