Django中使用websocket并实现简易聊天室

django使用websocket并实现简易聊天室

django默认只支持http协议

如果你想让django即支持http协议又支持websocket协议,则需要做以下配置

前期配置

前提需要安装channels:

channles的安装:

"""
注意事项
	1.不要安装最新版本的channles,建议安装2.3版本即可
	2.python解释器建议使用3.6
"""
pip3 install channels==2.3

1.配置文件中注册channels应用

INSTALLED_APPS = [
    # 1 注册channles应用
    'channels'
]

2.settings.py配置文件配置参数

# 2 配置启动需要的参数
ASGI_APPLICATION = 'myapi.routing.application'
# ASGI_APPLICATION = '项目名同名的文件夹名.内部的py文件名(默认就叫routing).routing文件内的变量名(默认就叫application)'

3.固定配置

# 在项目名同名的文件夹下创建routing.py文件并在该文件内提前写好以下代码
from channels.routing import ProtocolTypeRouter,URLRouter
from django.conf.urls import url
from app01 import consumers

application =ProtocolTypeRouter({
    'websocket':URLRouter([
        # websocket请求路由与视图函数的对应关系
      	url(r'^chat/$',consumers.ChatConsumer)
    ])
})

总结:配置完成后django由原来默认的wsgiref替换成asgi启动(asgi内部是基于达芙妮)

上述配置完成后 ,django就会同时支持http协议和websocket协议

"""
原先基于http协议的路由与视图函数对应关系还是跟之前一样urls.py、views.py

针对websocket协议的路由与视图函数对应关系则需要在routing.py和consumers.py(在对应的应用下创建即可)
"""

业务逻辑代码

# consumers.py
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer



class ChatConsumer(WebsocketConsumer):
    def websocket_connect(self, message):
        """
        客户端请求链接之后自动触发
        :param message: 消息数据
        """
        pass
    
    def websocket_receive(self, message):
        """
        客户端浏览器发送消息来的时候自动触发
        :param message: 消息数据
        """
        pass
    
    def websocket_disconnect(self, message):
        """
        客户端断开链接之后自动触发
        :param message:  
        """
        pass

基于channels完成聊天室

"""
http协议
	index	>>> index函数
	访问:浏览器发送请求即可

websocket协议
	chat >>> ChatConsumer类(3个方法)
	访问:借助于new WebSocket对象
"""
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer


consumer_object_list = []


class ChatConsumer(WebsocketConsumer):
    def websocket_connect(self, message):
        """
        客户端请求链接之后自动触发
        :param message: 消息数据
        """
        # print('请求链接')
        self.accept()  # 建立链接

        # 链接成功之后就将当前链接对象往列表中存一份
        consumer_object_list.append(self)


    def websocket_receive(self, message):
        """
        客户端浏览器发送消息来的时候自动触发
        :param message: 消息数据  {'type': 'websocket.receive', 'text': '你好啊 美女'}
        """
        # print(message)
        text = message.get('text')
        # 给客户端回复消息
        # self.send(text_data=text)
        # 我们要给所有的链接对象回复消息
        # 实现群发的简易版本
        for obj in consumer_object_list:
            obj.send(text_data=text)


    def websocket_disconnect(self, message):
        """
        客户端断开链接之后自动触发
        :param message:
        """
        # 客户端断开链接之后 应该将当前客户端对象从列表中移除
        consumer_object_list.remove(self)
        raise StopConsumer()  # 主动报异常 无需做处理 内部自动捕获
<h1>聊天室</h1>
<div>
    <input type="text" id="text" placeholder="请输入">
    <input type="button" value="发送" onclick="sendMsg()">
    <input type="button" value="断开链接" onclick="close()">
</div>

<h1>聊天纪录</h1>
<div id="content">

</div>

<script>
    var ws = new WebSocket('ws://127.0.0.1:8000/chat/');
    // 1 发送消息 ws.send()
    // 2 握手成功之后 自动触发  ws.onopen
    // 3 服务端发送消息过来 自动触发  ws.onmessage
    // 4 断开链接 ws.close()

    // 0 握手成功之后自动触发
    ws.onopen = function () {
        alert('建立成功')
    };

    // 1 给服务端发送消息
    function sendMsg() {
        ws.send($('#text').val());
    }

    // 2 接受服务端发送过来的消息
    ws.onmessage = function (event) {  // event是对象
        var dataValue = event.data;  // 获取服务端的数据
        // 用DOM操作将数据动态渲染到页面上
        var pEle = $('<p>');
        pEle.text(dataValue);
        $('#content').append(pEle)
    };

    // 3 断开链接
    function close() {
        ws.close()
    }
</script>

总结

"""
后端三个方法
	websocket_connect
	websocket_receive
	websocket_disconnect

前端四个方法
	// 1 发送消息 ws.send()
  // 2 握手成功之后 自动触发  ws.onopen
  // 3 服务端发送消息过来 自动触发  ws.onmessage
  // 4 断开链接 ws.close()
"""

注意我们上面的代码实现的群聊功能并不是真正的合理,后续如果想要真正实现群聊功能,官方提供了一个方法channel-layers模块,

posted @ 2020-02-29 00:48  tomjoy  阅读(2345)  评论(4编辑  收藏  举报