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会主动完成以上操作,只有基于AsyncConsumer
或SyncConsumer
自定义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>