基于Django?websocket實(shí)現(xiàn)視頻畫面的實(shí)時(shí)傳輸功能(最新推薦)
基于Django websocket實(shí)現(xiàn)視頻畫面的實(shí)時(shí)傳輸案例
??本案例是基于B/S架構(gòu)的視頻監(jiān)控畫面的實(shí)時(shí)傳輸,使用django作為服務(wù)端的開發(fā)框架。
Django Channels 是一個(gè)用于在 Django 框架中實(shí)現(xiàn)實(shí)時(shí)、異步通信的擴(kuò)展庫。傳統(tǒng)的 Django 是基于請(qǐng)求-響應(yīng)模式的,每個(gè)請(qǐng)求都會(huì)經(jīng)過 Django 的視圖函數(shù)進(jìn)行處理并返回響應(yīng)。而 Channels 提供了基于事件驅(qū)動(dòng)的編程模型,使得開發(fā)者可以處理實(shí)時(shí)的事件,如 WebSocket 連接、消息隊(duì)列、定時(shí)任務(wù)等。
Channels 的主要特性包括:
- 支持 WebSocket:Channels 可以輕松地處理 WebSocket 連接,實(shí)現(xiàn)實(shí)時(shí)的雙向通信;
- 異步處理:Channels 使用異步方式處理請(qǐng)求和事件,可以提高應(yīng)用的性能和并發(fā)能力;
- Channels 可以與諸如 Celery 等任務(wù)隊(duì)列庫集成,處理后臺(tái)任務(wù)和定時(shí)任務(wù)。
Channels可以跟Django無縫銜接,常用于開發(fā)聊天室、實(shí)時(shí)通知、實(shí)時(shí)數(shù)據(jù)更新等。
WebSocket 是一種在客戶端和服務(wù)器之間進(jìn)行雙向通信的網(wǎng)絡(luò)協(xié)議。與傳統(tǒng)的 HTTP 請(qǐng)求-響應(yīng)模式不同,WebSocket 只需要完成一次握手就可以創(chuàng)建持久性的連接,允許服務(wù)器主動(dòng)向客戶端推送數(shù)據(jù),而不需要客戶端發(fā)起請(qǐng)求。
在使用 WebSocket 進(jìn)行通信時(shí),涉及到異步和同步兩個(gè)概念:
在異步模式下,websocket使用異步的方式操作i/o,允許同時(shí)處理多個(gè)連接或事件。
在同步模式下,每個(gè) WebSocket 連接會(huì)被分配給一個(gè)線程或進(jìn)程進(jìn)行處理,消息的接收和發(fā)送是同步的操作。同步方式適用于一對(duì)一的連接事件。
環(huán)境配置
1、下載安裝channels庫
pip install channels
2、添加 Channels 到 Django 項(xiàng)目的安裝應(yīng)用列表中:打開 Django 項(xiàng)目的 settings.py
文件,在 INSTALLED_APPS
設(shè)置中添加 'channels'
,確保它出現(xiàn)在其他應(yīng)用的前面:
INSTALLED_APPS = [ ... 'channels', ... ]
并且在settings.py
文件添加以下內(nèi)容:
ASGI_APPLICATION = "projetc2.asgi.application" #project2為項(xiàng)目名稱 CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels.layers.InMemoryChannelLayer', }, }
Django Channels 運(yùn)行于 ASGI(Asynchronous Server Gateway Interface)協(xié)議上。ASGI 是一個(gè)用于處理異步 Python Web 應(yīng)用程序的協(xié)議,它提供了一種標(biāo)準(zhǔn)的方式來與 Web 服務(wù)器和應(yīng)用程序框架之間進(jìn)行通信。
3、配置 Channels 的 ASGI 應(yīng)用程序:在 Django 項(xiàng)目的根目錄下有一個(gè)名為 asgi.py
的文件,然后將文件中修改為以下內(nèi)容:
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', '項(xiàng)目名稱.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": URLRouter(routing.websocket_urlpatterns) })
4、配置 WebSocket 路由:在 Django 項(xiàng)目 project
的目錄下創(chuàng)建一個(gè)名為 routing.py
的文件,然后定義您的 WebSocket 路由。以下是一個(gè)示例:
from django.urls import re_path from app import consumers websocket_urlpatterns = [ re_path(r'ws/some-path1/$', consumers.TailfConsumer.as_asgi()), ]
5、創(chuàng)建 WebSocket 消費(fèi)者:在 myapp
應(yīng)用的目錄下創(chuàng)建一個(gè)名為 consumers.py
的文件,定義您的 WebSocket 消費(fèi)者類。
使用 Django WebSocket 實(shí)現(xiàn)循環(huán)發(fā)送圖像數(shù)據(jù)
當(dāng)使用 Django WebSocket 實(shí)現(xiàn)循環(huán)發(fā)送數(shù)據(jù)時(shí),可能會(huì)遇到 “took too long to shut down and was killed” 錯(cuò)誤。這個(gè)錯(cuò)誤通常是因?yàn)檠h(huán)發(fā)送數(shù)據(jù)的操作沒有正確終止導(dǎo)致的。
AsyncWebsocketConsumer
是 Django Channels 中用于處理 WebSocket 連接的異步消費(fèi)者類。它是一個(gè)基于協(xié)程的類,用于處理 WebSocket 連接的生命周期、接收和發(fā)送消息等操作。
創(chuàng)建一個(gè)繼承AsyncWebsocketConsumer
的自定義消費(fèi)者類
class TailfConsumer(AsyncWebsocketConsumer): async def connect(self): """ 這里定義連接建立時(shí)的邏輯 """ # 接受客戶端連接 await self.accept() # 開啟循環(huán)發(fā)送數(shù)據(jù) asyncio.ensure_future(self.send_data_loop()) async def disconnect(self, close_code): # 連接斷開時(shí)的邏輯 pass async def send_data_loop(self): while True: # 獲取數(shù)據(jù) data = await self.get_data() await self.send(json.dumps(data)) await asyncio.sleep(1) # 假設(shè)每秒發(fā)送一次數(shù)據(jù) async def get_data(self): """ 監(jiān)聽端口5000 ,實(shí)時(shí)獲取視頻圖像數(shù)據(jù) """ import pickle import socket # 創(chuàng)建客戶端 socket 對(duì)象 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 設(shè)置服務(wù)器地址和端口號(hào) server_address = ('192.168.1.106', 5000) # 連接服務(wù)器 client_socket.connect(server_address) decoded_data = {"leftimg":""} try: # 接收數(shù)據(jù) received_data = client_socket.recv(600000000) # 如果接收到數(shù)據(jù),則進(jìn)行處理 if received_data: try: decoded_data = pickle.loads(received_data) # 在這里處理解碼后的數(shù)據(jù) except pickle.UnpicklingError as e: # 處理解碼錯(cuò)誤 print(f"Failed to decode pickle data: {e}") client_socket.close() except Exception as e: print('接收數(shù)據(jù)時(shí)出錯(cuò):', str(e)) return decoded_data
async
和 await
是 Python 中用于定義和處理異步操作的關(guān)鍵字。它們與協(xié)程(coroutine)一起使用,以實(shí)現(xiàn)更高效的并發(fā)和非阻塞的編程。
創(chuàng)建一個(gè)腳本打開攝像頭模擬通過socket發(fā)送圖像數(shù)據(jù),由于直接打開攝像頭不能被多個(gè)用戶同時(shí)獲取數(shù)據(jù),所以采用這種方式實(shí)時(shí)發(fā)送數(shù)據(jù),腳本如下:
import pickle import socket import threading import cv2 import base64 video_source = 0 # 創(chuàng)建視頻捕獲對(duì)象 cap = cv2.VideoCapture(video_source) # 獲取視頻的寬度和高度 width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 用于存儲(chǔ)連接的客戶端 Socket client_sockets = [] import random # 生成一個(gè)包含19個(gè)隨機(jī)整數(shù)的列表 # 創(chuàng)建 socket 對(duì)象 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 綁定服務(wù)器地址和端口 server_address = ('192.168.1.106', 5000) server_socket.bind(server_address) # 監(jiān)聽客戶端連接 server_socket.listen(1) def image_to_base64(image): # 將圖像數(shù)據(jù)編碼為 Base64 字符串 image_base64 = base64.b64encode(image).decode('utf-8') return image_base64 # 定義發(fā)送視頻數(shù)據(jù)的函數(shù) def send_video_data(): while True: ret, frame = cap.read() if not ret: break # 將圖像編碼為 JPEG 格式 _, image_data = cv2.imencode('.jpg', frame) # 遍歷所有客戶端連接,發(fā)送視頻數(shù)據(jù) for client_socket in client_sockets: try: # 發(fā)送圖像數(shù)據(jù) 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) # 定義處理客戶端連接的函數(shù) def handle_client_connection(client_socket): while True: try: # 接收客戶端請(qǐng)求 data = client_socket.recv(1024) if not data: break # 處理客戶端請(qǐng)求 # 在此可以添加其他自定義邏輯 except Exception as e: print(f"Error handling client connection: {e}") break # 關(guān)閉客戶端連接 client_socket.close() client_sockets.remove(client_socket) # 接受客戶端連接,并啟動(dòng)視頻發(fā)送線程 def accept_client_connections(): while True: client_socket, _ = server_socket.accept() client_sockets.append(client_socket) # 啟動(dòng)視頻發(fā)送線程和客戶端連接接受線程 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) { // 接收到消息時(shí)的處理 const imageData = event.data; // 從事件中獲取圖像數(shù)據(jù) // 在前端顯示圖像數(shù)據(jù),這里假設(shè)有一個(gè)img元素來顯示圖像 const imgElement = document.getElementById('image'); imgElement.src = "data:image/jpeg;base64," + JSON.parse(imageData)["leftimg"]; }; socket.onclose = function(event) { console.log("WebSocket連接已關(guān)閉"); }; </script> </body> </html>
到此這篇關(guān)于基于Django websocket實(shí)現(xiàn)視頻畫面的實(shí)時(shí)傳輸案例的文章就介紹到這了,更多相關(guān)Django websocket實(shí)時(shí)傳輸內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Python中數(shù)據(jù)庫管理模塊shelve和dbm的應(yīng)用
作為常用的 python 自帶數(shù)據(jù)庫管理模塊,shelve 和 dbm 都是非常方便的對(duì)象持久化存儲(chǔ)和檢索工具,本文將從用法、優(yōu)勢(shì)以及不同點(diǎn)等方面進(jìn)行介紹,希望對(duì)大家有所幫助2023-10-10pytest fixtures裝飾器的使用和如何控制用例的執(zhí)行順序
這篇文章主要介紹了pytest fixtures裝飾器的使用和如何控制用例的執(zhí)行順序,幫助大家更好的理解和使用pytest測(cè)試框架,感興趣的朋友可以了解下2021-01-01Python-pandas返回重復(fù)數(shù)據(jù)的index問題
這篇文章主要介紹了Python-pandas返回重復(fù)數(shù)據(jù)的index問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02Python 實(shí)現(xiàn)一行輸入多個(gè)值的方法
下面小編就為大家分享一篇Python 實(shí)現(xiàn)一行輸入多個(gè)值的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-04-04pycharm 中mark directory as exclude的用法詳解
今天小編就為大家分享一篇pycharm 中mark directory as exclude的用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-02-02