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

