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链接不断发送消息,服务器端自执行函数触发咱们的查询,形成一个伪实时。不知道是否有更好的方法?

相关文章
相关标签/搜索