Channels3.0.3
网上的教程是2.4.0,本文照着官方文档整合。
Installation — Channels 3.0.3 documentation
https://channels.readthedocs.io/en/stable/installation.html
版本:
Python 3.7
Django 3.2.2
Channels 3.0.3
python -m pip install -U channels
简单使用
新建项目,新建app,略。(本文新建的app名称为TestModel)
setting.py添加channels和ASGI_APPLICATION :
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
...
'channels',
)
ASGI_APPLICATION = 'mysite.asgi.application'#mysite改为自己的项目名
asgi.py修改成:
import os
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from channels.auth import AuthMiddlewareStack
import TestModel.routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hat.settings')
django_application = get_asgi_application()
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
TestModel.routing.websocket_urlpatterns
)
),
})
在新建的app创建TestModel/routing.py,跟urls.py一样用来跳转
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),
]
app中新建TestModel/consumers.py,用来处理请求,.as_asgi()作用跟Django的as_view()一样,将类作为返回。
from channels.generic.websocket import WebsocketConsumer
class ChatConsumer(WebsocketConsumer):
def connect(self):
print("Connect")
self.accept()
def disconnect(self, close_code):
pass
def receive(self, text_data):
print("收到消息:"+text_data)
self.send(text_data=json.dumps({
'message': text_data
}))
运行服务器
python3 manage.py migrate
python3 manage.py runserver
使用测试工具或者浏览器打开控制台
在线websocket测试-在线工具-postjson
http://coolaf.com/tool/chattest
控制台依次输入(端口修改成自己的):
ws = new WebSocket(‘ws://localhost:9300/ws/chat/test/’)
ws.onmessage = event => console.log(event.data)
ws.send(“ping”)
另一种写法
asgi.py
import os
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from .websocket import websocket_application
from channels.auth import AuthMiddlewareStack
import TestModel.routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hat.settings')
django_application = get_asgi_application()
async def application(scope, receive, send):
if scope['type'] == 'http':
# Let Django handle HTTP requests
await django_application(scope, receive, send)
elif scope['type'] == 'websocket':
print("websocket")
await websocket_application(scope, receive, send)
else:
raise NotImplementedError(f"Unknown scope type {scope['type']}")
同目录下新建websocket.py
async def websocket_application(scope, receive, send):
while True:
event = await receive()
print(event['type'])
if event['type'] == 'websocket.connect':
await send({
'type': 'websocket.accept'
})
if event['type'] == 'websocket.disconnect':
break
if event['type'] == 'websocket.receive':
if event['text'] == 'ping':
await send({
'type': 'websocket.send',
'text': 'pong!'
})
多用户 Group
多个consumer同时连接的时候,需要通信就要使用到group
需要用到Synchronous
setting.py增加:
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
上面这个需要redis pip install channels_redis
可以使用下面这个配置:
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer"
}
}
不要在生产环境使用此配置!
将原来的consumer.py改写为:
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
# Receive message from room group
async def chat_message(self, event):
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
发送json格式数据:
{“message”: “hi”}
新开另一个网页,连接同一地址,可以收到别的用户发来的消息。
错误
错误:
Exception inside application: ERR unknown command ‘BZPOPMIN’
解决:升级redis5.0以上