Django - WebSocket:dwebsocket


什么是WebSocket

WebSocket是一種在單個TCP連接上進行全雙工通信的協議

WebSocket使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在WebSocket API中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,並進行雙向數據傳輸

現在,很多網站為了實現推送技術,所用的技術都是輪詢。輪詢是在特定的的時間間隔(如每1秒),由瀏覽器對服務器發出HTTP請求,然后由服務器返回最新的數據給客戶端的瀏覽器。這種傳統的模式帶來很明顯的缺點,即瀏覽器需要不斷的向服務器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的數據可能只是很小的一部分,顯然這樣會浪費很多的帶寬等資源。

而比較新的技術去做輪詢的效果是Comet。這種技術雖然可以雙向通信,但依然需要反復發出請求。而且在Comet中,普遍采用的長鏈接,也會消耗服務器資源。

在這種情況下,HTML5定義了WebSocket協議,能更好的節省服務器資源和帶寬,並且能夠更實時地進行通訊。

很可能用不到的判斷

WebSocket 協議在2008年誕生,2011年成為國際標准,所有瀏覽器都已經支持了。你可以這么判斷瀏覽器是否支持:

<script>
    if ('WebSocket' in window) {
        console.log('你的瀏覽器支持 WebSocket')
    }
</script>

WebSocket for Django

django實現websocket大致上有兩種方式,一種channels,一種是dwebsocket。channels依賴於redis,twisted等,相比之下使用dwebsocket要更為方便一些。

Install dwebsocket

pip install dwebsocket  # 最新版
# 網上貌似說最新的不好用,我們可以下載大家使用較多的老版本
pip install dwebsocket==0.4.2

我開始就下的默認版本,然后報錯:

AttributeError: 'WSGIRequest' object has no attribute 'is_websocket'

后來下載老版本就好了。

服務端常用方法或者屬性

名稱 描述 備注
@accept_websocket 處理websocket和HTTP請求 該裝飾器用的較多
@require_websocket 僅處理websocket請求,拒絕HTTP請求
request.is_websocket() 如果請求類型是websocket,返回True,否則返回False 通常與@accept_websocket裝飾器搭配
request.websocket 當websocket請求建立后,該請求具有一個websocket屬性,可以通過該屬性進行通信, 如果request.is_websocket()是False,則這個屬性為None。
request.websocket.wait() 阻塞接收消息
request.websocket.read() 非阻塞接收消息
request.websocket.count_messages() 返回隊列中的消息數量
request.websocket.has_messages() 如果有新消息返回True,否則返回False
request.websocket.send() 向客戶端發送bytes類型的數據
request.websocket.close() 服務器端主動關閉websocket服務
request.websocket._iter_() websocket迭代器

客戶端的屬性和方法

名稱 類型 描述
WebSocket 對象 提供到服務端的雙向通道
onopen 屬性 當websocket連接時調用的事件處理程序
onmessage 屬性 通知接收到消息的事件處理程序
onerror 屬性 當出現錯誤時調用的事件處理程序
onclose 屬性 當套接字關閉時調用的事件處理程序
readState 屬性 報告websocket連接狀態
close 方法 關閉websocket
send 方法 使用websocket向服務端發送數據
url 屬性 報告套接字的當前URL
protocol 屬性 報告服務器所選中的協議
binaryType 屬性 由onmessage接收的二進制數據格式
bufferedAmount 屬性 使用send的已排隊的數據字節數
extensions 屬性 包括服務器所選中的擴展名

關於readState,根據readState屬性可以判斷websocket的連接狀態,該屬性的值可以是以下幾種:

屬性值 對應常量 描述 備注
0 CONNECTING 正在建立連接 但還沒有建立完畢
1 OPEN 連接成功建立,可以進行通信
2 CLOSING 連接正在關閉 即將關閉
3 CLOSED 連接已關閉 或者根本沒有建立連接

根據bufferedAmount可以知道有多少字節的數據等待發送,若websocket已經調用了close方法該屬性將會一直增長。

必要的settings配置

settings.py

MIDDLEWARE_CLASSES = [
    'dwebsocket.middleware.WebSocketMiddleware'
]
WEBSOCKET_ACCEPT_ALL=True  # 可以允許每一個單獨的視圖實用websocket

添加上這個中間件,就會拒絕單獨的視圖使用websocket,不過我們一般都是使用視圖搭配websocket,所以,這個配置忘掉吧,順便把第二個配置也忘掉,除非你要搞復雜的操作......

示例

環境

django1.11 + Python3.6 + PyCharm2018.1 + win10

Django中的配置

settings中保持默認即可

urls.py

from django.conf.urls import url
from django.contrib import admin
from web import views   # web是我的APP名稱

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test/', views.test, name='test'),
]

views.py

import time
from django.shortcuts import render
from dwebsocket.decorators import accept_websocket


@accept_websocket
def test(request):
    if request.is_websocket():
        print('websocket connection....')
        msg = request.websocket.wait()  # 接收前端發來的消息
        print(msg, type(msg), json.loads(msg))  # b'["1","2","3"]' <class 'bytes'> ['1', '2', '3']
        while 1:
            if msg:
                # 你要返回的結果
                for i in range(10):
                    request.websocket.send('service message: {}'.format(i).encode())  # 向客戶端發送數據
                    time.sleep(0.5)  # 每0.5秒發一次
                request.websocket.close()
    else:  # 如果是普通的請求返回頁面
        return render(request, 'test.html')

test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>test</title>
</head>
<body>
<div></div>

</body>
<!-- 首先引入 jQuery -->
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script>
    // 判斷瀏覽器是否支持WebSocket,目前應該所有的瀏覽器都支持了.....
    if ('WebSocket' in window) {
        console.log('你的瀏覽器支持 WebSocket')
    }
	// 創建一個WebSocket對象:sk,並且建立與服務端的連接(服務端程序要跑着哦)
    var sk = new WebSocket('ws://' + window.location.host + '/test/');
    // 向服務端發送消息
    sk.onopen = function () {
        console.log('websocket connection successful...');
        var l = ['1', '2', '3'];
        sk.send(JSON.stringify(l));
    };
    // 接收服務端的消息,主要的業務邏輯也在這里完成
    sk.onmessage = function (msg) {
        // 業務邏輯
        html = "<p>" + msg.data + "</p>";
        $("div").append(html);
        console.log('from service message: ', msg.data);
        // 由於服務端主動斷開連接,這里也斷開WebSocket連接
        if (sk.readyState == WebSocket.CLOSED) sk.close();
    };
    // 完事就關閉WebSocket連接
    sk.onclose = function (msg) {
        console.log('websocket connection close...');
        sk.close()
    };
    // 當WebSocket連接創建成功后,我們就可以向服務端發送數據了
    if (sk.readyState == WebSocket.OPEN) sk.onopen();

</script>
</html>

歡迎斧正,that's all see also:[websocket知識匯總以及websocket在Django中的實現]( ) | [dwebsocket 0.5.11]( ) | [利用dwebsocket在Django中使用Websocket]( ) | [django中使用dwebsocket 后端實時進行和前端通訊]( ) | [Django實現websocket完成實時通訊、聊天室、在線客服等](https://www.cnblogs.com/sui776265233/p/10176275.html)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM