Django基于websocket实现群聊功能

Django基于websocket实现群聊功能

Django支持http协议和websocket协议,并且可以识别不同协议请求的原因是channels的ProtocolTypeRouter类的下面代码:

#支持http协议和websocket的源代码
class ProtocolTypeRouter:
    """
    Takes a mapping of protocol type names to other Application instances,
    and dispatches to the right one based on protocol name (or raises an error)
    """
    def __init__(self, application_mapping):
        self.application_mapping = application_mapping
        if "http" not in self.application_mapping:
            self.application_mapping["http"] = AsgiHandler

关于django支持websocket的配置见上一篇文章。

简易聊天室实现思路

"""
http协议
	index					>>>			index函数
	访问:浏览器地址栏输入地址直接访问聊天页面
	
websocket协议
	url配置为url(r'^chat/$',consumers.ChatConsumer)使用ChatConsumer类的方法对前端发送过来的数据进行处理,并群发
	访问:利用js内置对象new WebSocket('ws://127.0.0.1:8080/chat/')
"""

ChatConsumer的方法介绍

websocket_connect请求websocket连接的时候自动触发
websocket_receive前端浏览器发送消息时自动触发
websocket_disconnect断开websocket连接时自动触发
class ChatConsumer(WebsocketConsumer):
    def websocket_connect(self, message):
        """请求websocket链接的时候自动触发"""
        # print('请求链接')
        self.accept()  # 与客户端建立链接
    def websocket_receive(self, message):
        """前端浏览器发送消息自动触发"""
        print(message)  # 消息字典  {'type': 'websocket.receive', 'text': 'hahahaha'}
        # 给客户端发消息
        msg = message.get('text')
        for obj in consumer_obj_list:
            obj.send(text_data=msg)

    def websocket_disconnect(self, message):
        """断开websocket链接自动触发"""
        # print('断开链接')
        raise StopConsumer

前端websocket对象法介绍

onopen握手环节成功之后自动触发
send发送数据到服务端
onmessage服务端发送数据时触发
onclose浏览器断开连接时执行
close关闭websocket对象与服务端的连接
<script>
    // 生产内置对象
    var ws = new WebSocket('ws://127.0.0.1:8000/chat/');

    // 1 握手环节成功之后自动触发  onopen
    ws.onopen = function () {
        console.log('链接成功')
    };
    // 2 发送数据       send
    function sendMsg() {
        ws.send($('#d1').val())
    }

    // 3 服务端发送数据自动触发   onmessage
    ws.onmessage = function (args) {
        // alert(args)  // args不是真正的数据对象 真正的数据在该对象的data属性中
        alert(args.data)
    };
    // 4 浏览器断开链接        close
    ws.onclose = function () {
        ws.close()
    }
</script>

StopConsumer

当连接到consumer的链接关闭时,服务器会收到一个相应的event(比如,http.disconnect或websocket.disconnect),应用接受后需要作相应的处理。处理完成后,应当触发channels.exceptions.StopConsumer以彻底中止ASGI应用。如果不出发并任由应用运行,则服务器会在达到应用关闭时限后(Daphne默认10秒),结束应用并触发警告。
通用型consumer会主动完成以上操作,只有基于AsyncConsumerSyncConsumer自定义consumer时需要注意这些。

关于channels的consumer的详细介绍参考链接:

https://blog.csdn.net/JosephThatwho/article/details/102614787

实现群聊功能代码

在app里新建consumer.py并进行如下配置

from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer

consumer_obj_list = []

class ChatConsumer(WebsocketConsumer):
    def websocket_connect(self, message):
        """请求websocket链接的时候自动触发"""
        # print('请求链接')
        self.accept()  # 与客户端建立链接
        consumer_obj_list.append(self)
    def websocket_receive(self, message):
        """前端浏览器发送消息自动触发"""
        print(message)  # 消息字典  {'type': 'websocket.receive', 'text': 'hahahaha'}
        # 给客户端发消息
        msg = message.get('text')
        for obj in consumer_obj_list:
            obj.send(text_data=msg)

    def websocket_disconnect(self, message):
        """断开websocket链接自动触发"""
        # print('断开链接')
        raise StopConsumer
        

routing.py

from channels.routing import ProtocolTypeRouter,URLRouter
from django.conf.urls import url
from app01 import consumers

application = ProtocolTypeRouter({
    'websocket':URLRouter([
        # websocket相关的url与视图函数对应关系
        url(r'^chat/$',consumers.ChatConsumer)
    ])
})
<body>
<h1>聊天室</h1>
<div>
    <input type="text" id="d1">
    <button onclick="sendMsg()">发送</button>
</div>
<h1>聊天纪录</h1>
<div id="record"></div>

<script>
    // 生产内置对象
    var ws = new WebSocket('ws://127.0.0.1:8080/chat/');

    // 1 握手环节成功之后自动触发  onopen
    ws.onopen = function () {
        console.log('链接成功')
    };
    // 2 发送数据       send
    function sendMsg() {
        ws.send($('#d1').val())
    }

    // 3 服务端发送数据自动触发   onmessage
    ws.onmessage = function (args) {
        // alert(args)  // args不是真正的数据对象 真正的数据在该对象的data属性中
        {#alert(args.data)#}
        // 将聊天纪录渲染到页面上
        pEle = $('<p>');
        pEle.text(args.data);
        $('#record').append(pEle)
    };
    // 4 浏览器断开链接        close
    ws.onclose = function () {
        ws.close()
    }
</script>
</body>
posted @ 2020-03-17 19:31  ylpb  阅读(542)  评论(0编辑  收藏  举报