django 實現websocket

1、簡述:django實現websocket,以前django-websocket退出到3.0以後,被廢棄。官方推薦你們使用channels。javascript

channels經過升級http協議 升級到websocket協議。保證明時通信。也就是說,咱們徹底能夠用channels實現咱們的即時通信。而不是使用長輪詢和計時器方式來保證僞實時通信。html

他經過改造django框架,使django既支持http協議又支持websocket協議。前端

官方文檔地址:https://channels.readthedocs.io/en/stable/html5

二:安裝java

python version:2.7 3.4 3.5python

安裝channels:web

1 pip install -U channels

在安裝在windows機器的時候。須要自信的C++支持,報錯的時候,報錯有地址告訴你下載URL。django

配置:windows

須要在seting.py裏配置,將咱們的channels加入INSTALLED_APP裏。後端

1 INSTALLED_APPS = ( 2     'django.contrib.auth', 3     'django.contrib.contenttypes', 4     'django.contrib.sessions', 5     'django.contrib.sites', 6  ... 7     'channels', 8 )

這樣django就支持websocket了,接下來咱們須要配置一些簡單的配置。

三:概念闡述:

channels: It is an ordered, first-in first-out queue with message expiry and at-most-once delivery to only one listener at a time.

它是先進先出的消息隊列,同一時刻只向一個消費者發送一個沒有過時的消息。這裏的消費者相似訂閱者,或者客戶端。

默認的channels是http.request.在這種狀況下運行 django 和以前的沒使用websocket來講沒有什麼特別。

經過查看源碼咱們能夠看到其餘的channels:

至於咱們是否能夠自定義channels目前沒有驗證!

介紹下channels結構:

首先須要創建一個django項目。其中在你本身的app下面 生成consumers.py和routing.py配置文件。

consumers.py:至關於django的視圖,也就是說全部的websocket路由過來的執行的函數都在consumers.py相似於django的視圖views.py

routing.py:是websocket中的url和執行函數的對應關係。至關於django的urls.py,根據映射關係,當websocket的請求進來的時候,根據用戶的請求來觸發咱們的consumers.py裏的方法。

四:代碼示例

consumer.py

 
1 # In consumers.py 2 
3 def ws_message(message): 4     # ASGI WebSocket packet-received and send-packet message types 5     # both have a "text" key for their textual data. 6  message.reply_channel.send({ 7         "text": message.content['text'], 8     })

 

routing.py

1 # In routing.py 2 from channels.routing import route 3 from myapp.consumers import ws_message 4 
5 channel_routing = [ 6     route("websocket.receive", ws_message), 7 ]

 

websocket.receive表示當用戶請求的時候,自動觸發後面的ws_message.

html  code:html5支持websocket。

 1 <!DOCTYPE HTML>
 2 <html>
 3    <head>
 4    <meta charset="utf-8">
 5    <title>測試websocket</title>
 6 
 7       <script type="text/javascript">
 8  function WebSocketTest()  9  { 10             if ("WebSocket" in window) 11  { 12                alert("您的瀏覽器支持 WebSocket!"); 13 
14                // 打開一個 web socket
15                 ws = new WebSocket("ws://localhost:8000/path/"); 16 
17                ws.onopen = function() 18  { 19                   // Web Socket 已鏈接上,使用 send() 方法發送數據
20                   ws.send("發送數據"); 21                   alert("數據發送中..."); 22  }; 23 
24                ws.onmessage = function (evt) 25  { 26                   var received_msg = evt.data; 27                   alert("數據已接收..."); 28                   alert("數據:"+received_msg) 29  }; 30 
31                ws.onclose = function() 32  { 33                   // 關閉 websocket
34                   alert("鏈接已關閉..."); 35  }; 36  } 37 
38             else
39  { 40                // 瀏覽器不支持 WebSocket
41                alert("您的瀏覽器不支持 WebSocket!"); 42  } 43  } 44       </script>
45 
46    </head>
47    <body>
48 
49       <div id="sse">
50          <a href="javascript:WebSocketTest()">運行 WebSocket</a>
51       </div>
52 
53    </body>
54 </html>

演示:

1:

2:

3:

4:

5:

 五:如上是簡單實現 咱們的websocket 例子 ,其中channels來還有以下類型:

1 websocket.connect 剛創建鏈接。 2 
3 websocket.disconnect 鏈接斷開的時候

能夠根據本身的需求來在routing裏定義  在觸發websocket各個階段的時候執行函數。

目前實現的是一個客戶端進行操做,也就是說一個consumer的狀況,當咱們的有多個consumer的時候,怎麼保證server端發送消息全部的consumer都能接受到呢?

channels給我們定義個group概念。也就是說只要consumer和這個組創建的關係,其餘的各個consumer都會接受到消息。

consumer.py

 1 # In consumers.py  2 from channels import Group  3 
 4 # Connected to websocket.connect  5 def ws_add(message):  6     message.reply_channel.send({"accept": True})  7     Group("chat").add(message.reply_channel)  8 
 9 # Connected to websocket.receive 10 def ws_message(message): 11     Group("chat").send({ 12         "text": "[user] %s" % message.content['text'], 13  }) 14 
15 # Connected to websocket.disconnect 16 def ws_disconnect(message): 17     Group("chat").discard(message.reply_channel)

 

routing.py:

1 from channels.routing import route 2 from myapp.consumers import ws_add, ws_message, ws_disconnect 3 
4 channel_routing = [ 5     route("websocket.connect", ws_add), 6     route("websocket.receive", ws_message), 7     route("websocket.disconnect", ws_disconnect), 8 ]

在瀏覽器輸入以下js:

 1 // Note that the path doesn't matter right now; any WebSocket  2 // connection gets bumped over to WebSocket consumers
 3 socket = new WebSocket("ws://" + window.location.host + "/chat/");  4 socket.onmessage = function(e) {  5  alert(e.data);  6 }  7 socket.onopen = function() {  8     socket.send("hello world");  9 } 10 // Call onopen directly if socket is already open
11 if (socket.readyState == WebSocket.OPEN) socket.onopen();

 

咱們打開2個瀏覽器進行測試:

當咱們運行窗口二的js的時候窗口也能接受到消息。

這是由於服務端以組來發送消息。

1    Group("chat").send({ 2         "text": "[user] %s" % message.content['text'], 3     })

根據以上特性 咱們能夠建立咱們的聊天室。

其中routing.py中支持正則路徑匹配,咱們能夠根據咱們的需求,由用戶根據路徑不一樣請求不一樣的聊天室,想深刻了解,請參考官方文檔。

爲何研究websocket?

由於在實際生產中,咱們須要有一個即時通信的,不斷請求後端結果。來反映在頁面。可是,channels測試的過程當中,consumer中的函數體不能加入while循環,

測試的結果是:只有當consumer裏的函數執行完,才能所有發送到客戶端消息,而不是有消息就能發送。

最後的解決方案:只能前端使用計時器同一個tcp鏈接不斷髮送消息,服務器端自執行函數觸發咱們的查詢,形成一個僞實時。不知道是否有更好的方法?

相關文章
相關標籤/搜索