django中如何实现websocket,真正通过websocket实现群聊功能
django中如何实现websocket
安装
pip3 install channles==2.3
1 解释器版本建议使用python3.6
2 channles模块版本建议使用2.3
基本配置
配置文件中注册app
配置文件中定义配置
对应应用下新建py文件并且在文件内部定义变量
完成上述配置以后,django就会既支持http又支持websocket
django,pycharm创建的django项目会自动帮你创建全局的templates文件夹,
也可以在每一个应用下创建templates模板文件夹
如果出现多个应用和全局都有模板文件夹的情况,会优先查找全局,如果全局没有,会按照配置文件中注册的app的顺序从上往下依次进行查找每一个应用下的templates
每一个应用都可以有自己的urls.py,views.py和templates,static
配置完成以后同时支持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
配置完成以后
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)
])
})
consumers.py
from channels.generic.websocket import WebsocketConsumer
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""客户端请求建立链接时 自动触发"""
pass
def websocket_receive(self, message):
"""客户端发送数据过来 自动触发"""
pass
def websocket_disconnect(self, message):
"""客户端断开链接之后 自动触发"""
pass
"""
http协议
index路径 index视图函数
访问:浏览器窗口直接输入的地址的
websocket协议
chat路径 ChatConsumer视图类
访问:new WebSocket对象访问
"""
真正通过websocket实现群聊功能:
通过自己维护一个列表存储链接对象的方式完成了简易版本的群聊,其实还可以用channels提供的模块,channel-layers
# 后端 三个方法
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
consumer_object_list = []
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
# 客户端请求链接时 自动触发
print('请求链接')
self.accept()
# 建立链接 并且自动帮你维护每一个客户端
# 将链接在列表中存储一份
consumer_object_list.append(self)
def websocket_receive(self, message):
# 客户端发送数据过来 自动触发
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):
# 客户端断开链接之后 自动触发
print('断开链接')
# 客户端断开之后,应该将当前对象移除
consumer_object_list.remove(self)
raise StopConsumer()
# 前端四个方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>聊天室</h1>
<input type="text" id="txt">
<button onclick="sendMsg()">发送</button>
<h1>聊天记录</h1>
<div class="record"></div>
<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($('#txt').val())
}
// 3 服务端一旦有了消息 自动触发 onmessage
ws.onmessage = function (args) {
// 获取发送的数据
// 创建p标签
var pEle = $('<p>');
pEle.text(args.data);
$('.record').append(pEle)
};
// 4 断开链接之后 自动触发 onclose
ws.onclose = function () {
ws.close()
}
</script>
</body>
</html>