• django 实现websocket


    一、简述:django实现websocket,之前django-websocket退出到3.0之后,被废弃。官方推荐大家使用channels。

    channels通过升级http协议 升级到websocket协议。保证实时通讯。也就是说,我们完全可以用channels实现我们的即时通讯。而不是使用长轮询和计时器方式来保证伪实时通讯。

    他通过改造django框架,使django既支持http协议又支持websocket协议。

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

    二:安装

    python version:2.7 3.4 3.5

    安装channels:

    1 pip install -U channels

    在安装在windows机器的时候。需要自信的C++支持,报错的时候,报错有地址告诉你下载URL。

    配置:

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

  • 相关阅读:
    kafka消费者问题
    kubernetes
    Grafana+prometheus+AlertManager+钉钉机器人
    kafka汇总
    java实现顺序表、链表、栈 (x)->{持续更新}
    hadoop细节 -> 持续更新
    drf之组件(认证、权限、排序、过滤、分页等)和xadmin、coreapi
    drf之视图类与路由
    drf序列化与反序列化
    drf之接口规范
  • 原文地址:https://www.cnblogs.com/caodneg7/p/10446715.html
Copyright © 2020-2023  润新知