Python Channels模块使用
Django初步配置Channels模块
安装Channels模块
pip install channels==3.0.3
***注意:不要直接pip install channels,会导致安装最新的channels包导致后面无法使用asgi文件
在settings文件中注册app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'channels',
'app01.apps.App01Config',
]
在settings文件中使用引入asgi文件
ASGI_APPLICATION = 'long_poll.asgi.application'
***long_poll为自己的项目名称
asgi文件中配置如下:
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from . import routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'long_poll.settings') # long_poll为自己项目名称
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": URLRouter(routing.websocket_urlpatterns),
})
创建routing文件并配置路由(与Django创建路由到视图函数类似):
from django.urls import re_path
from app01 import consumers
websocket_urlpatterns = [
re_path(r'ws/(?P<group>\w+)/$',consumers.ChatConsumer.as_asgi()),
]
编写视图函数(创建consumers文件):
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""有客户端来向后端发送连接时,就会自动触发"""
print('有人来连接了')
self.accept()
def websocket_receive(self, message):
"""浏览器基于websocket向后端发送数据时自动触发,用于接收数据"""self.send('不要回复')
def websocket_disconnect(self, message):
"""客户端向后端断开连接时自动触发"""
print('断开连接')
raise StopConsumer()
客户端向服务端发送消息
编写Django视图函数(view.py文件):
from django.shortcuts import render, HttpResponse
def home(request):
return render(request, 'home.html')
在templates文件夹下创建 home.html (客户端)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.message {
height: 500px;
width: 100%;
border: 1px solid #e0e0e0;
}
</style>
</head>
<body>
<div class="message" id="myDiv"></div>
<div>
<input type="text" placeholder="请输入" id="txt">
<input type="button" value="发送" onclick="sendMessage()">
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
<script>
socker=new WebSocket("ws://127.0.0.1:8000/ws/123/") //创建一个WebSocket对象
function sendMessage(){
let tag=document.getElementById('txt')
socker.send(tag.value) //向服务端发送信息
}
</script>
</body>
</html>
服务端接收到消息(consumers.py文件)
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""有客户端来向后端发送连接时,就会自动触发"""
print('有人来连接了')
self.accept()
def websocket_receive(self, message):
"""浏览器基于websocket向后端发送数据时自动触发,用于接收数据"""
print('我接受到了消息----->',message)
# self.send('不要回复')
def websocket_disconnect(self, message):
"""客户端向后端断开连接时自动触发"""
print('断开连接')
raise StopConsumer()
服务端给客户端主动发送消息:
客户端(home.html文件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.message {
height: 500px;
width: 100%;
border: 1px solid #e0e0e0;
}
</style>
</head>
<body>
<div class="message" id="myDiv"></div>
<div>
<input type="text" placeholder="请输入" id="txt">
<input type="button" value="发送" onclick="sendMessage()">
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
<script>
socker=new WebSocket("ws://127.0.0.1:8000/ws/123/") //创建一个WebSocket对象
// 回调函数,当websocket接收到服务端发来的消息时自动触发此函数
socker.onmessage=function (event){
console.log(event.data)
}</script>
</body>
</html>
服务端(consumers.py文件):
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""有客户端来向后端发送连接时,就会自动触发"""
print('有人来连接了')
self.accept()
"""握手完成后,给客户端发送消息"""
self.send('你好呀')
客户端断开连接
客户端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.message {
height: 500px;
width: 100%;
border: 1px solid #e0e0e0;
}
</style>
</head>
<body>
<div class="message" id="myDiv"></div>
<div>
<input type="text" placeholder="请输入" id="txt">
<input type="button" value="关闭" onclick="closeConn()">
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
<script>
socker=new WebSocket("ws://127.0.0.1:8000/ws/123/") //创建一个WebSocket对象
function closeConn(){
socker.close() //客户端断开连接
}
</script>
</body>
</html>
服务端
客户端触发socker.close()后,自动触发服务端的websocket_disconnect()函数
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""有客户端来向后端发送连接时,就会自动触发"""
self.accept()
"""握手完成后,给客户端发送消息"""
self.send('你好呀')
def websocket_receive(self, message):
"""浏览器基于websocket向后端发送数据时自动触发,用于接收数据"""
self.send('不要回复')
def websocket_disconnect(self, message):
"""客户端向后端断开连接时自动触发"""
print('断开连接')
raise StopConsumer()
基于channels中提供channel layers来实现
在settings中配置
CHANNEL_LAYERS = {
'default': {
"BACKEND": "channels.layers.InMemoryChannelLayer"
}
}
使用channel-redis配置(选其中之一就行了)
pip install channel-redis
在settings中配置
CHANNEL_LAYERS = {
'default': {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [('127.0.0.1', 6379)]
}
}
}
views.py文件,接收前端传来的组号
from django.shortcuts import render, HttpResponse
def home(request):
num = request.GET.get('num')
return render(request, 'home.html', {'num': num})
home.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.message {
height: 500px;
width: 100%;
border: 1px solid #e0e0e0;
}
</style>
</head>
<body>
<div class="message" id="myDiv"></div>
<div>
<input type="text" placeholder="请输入" id="txt">
<input type="button" value="发送" onclick="sendMessage()">
<input type="button" value="关闭" onclick="closeConn()">
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
<script>
socker = new WebSocket("ws://127.0.0.1:8000/ws/{{num}}/") //创建一个WebSocket对象
// 回调函数,接收服务端发来的消息
socker.onmessage = function (event) {
// console.log(event.data)
// 找到你想要添加元素的div
var myDiv = document.getElementById('myDiv');
// 创建一个新的p元素
var newElement = document.createElement('p');
// 设置p元素的内容
newElement.textContent = event.data;
// 将新创建的p元素添加到div中
myDiv.appendChild(newElement);
}
function sendMessage() {
let tag = document.getElementById('txt')
socker.send(tag.value) //向服务端发送信息
}
function closeConn() {
socker.close()
}
</script>
</body>
</html>
consumers.py文件
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
from asgiref.sync import async_to_sync
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""有客户端来向后端发送连接时,就会自动触发"""
self.accept()
"""将连接对象加入到内存或redis中"""
group = self.scope['url_route']['kwargs'].get('group')
async_to_sync(self.channel_layer.group_add)(group, self.channel_name)
def websocket_receive(self, message):
"""浏览器基于websocket向后端发送数据时自动触发,用于接收数据"""
group = self.scope['url_route']['kwargs'].get('group')
"""通知组内的所有客户端,执行xx_oo的方法,在此方法中可以定义任意的功能"""
async_to_sync(self.channel_layer.group_send)(group, {'type': 'xx.oo', 'message': message})
def xx_oo(self, message):
self.send(message['message']['text'])
def websocket_disconnect(self, message):
"""客户端向后端断开连接时自动触发"""
group = self.scope['url_route']['kwargs'].get('group')
async_to_sync(self.channel_layer.group_discard)(group, self.channel_name)
raise StopConsumer()

浙公网安备 33010602011771号