今天介绍下在django中使用channels实现websocket的步骤。
首先介绍下channels。
channels官方文档连接如下:
https://channels.readthedocs.io/en/latest/
channels这个第三方包可以帮助django在http之上扩展很多功能,可以使django实现websocket,聊天协议等。channels可以使django运行在同步模式下,但是异步的处理connections和socket。
下面介绍在django中,使用channels实现websocket功能。下面DjangoChannel是项目名称,test01是app名称。
环境
python3.6 channels2.1.7 channels-redis2.3.3 django2.0.5 drf3.9.2
前端页面
index.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <!DOCTYPE html> <html> <head> <title>cchannels实现websocket</title> <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script> <script type="text/javascript"> $(function () { $('#sendMsg').click(function () { var socket = new WebSocket("ws://127.0.0.1:8000/ws/status/1") socket.onopen = function () { console.log('WebSocket open') socket.send($('#msg').val()) } socket.onmessage = function (ret) { var data = JSON.parse(ret.data) var msg = data["message"] console.log('message: ' + msg) $('#retMsg').prepend('<p>' + msg + '</p>') } }) }) </script> </head> <body> <br> <input type="text" id="msg" value="Hello, World!"/> <button type="button" id="sendMsg">发送</button> <h1>Received Messages</h1> <div id="retMsg"></div> </body> </html>
|
routing配置
test01/routing.py:
1 2 3 4 5 6 7
| from django.urls import path from . import consumers
websocket_urlpatterns = [ path('ws/status/<client_id>', consumers.ServiceConsumer), ]
|
DjangoChannel/routing.py:
1 2 3 4 5 6 7 8 9 10 11 12
| from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter import test01.routing
application = ProtocolTypeRouter({ 'websocket': AuthMiddlewareStack( URLRouter( test01.routing.websocket_urlpatterns ) ) })
|
consumer的编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| import json from channels.generic.websocket import AsyncWebsocketConsumer
class ServiceConsumer(AsyncWebsocketConsumer): async def connect(self): """ 连接成功后执行该函数 :return: """ self.client_id = self.scope['url_route']['kwargs']['client_id'] self.room_group_name = 'group_%s' % self.client_id
print("scope:", self.scope) print("client id:", self.client_id) print("channel layer:", self.channel_layer) print("channel name:", self.channel_name) print("room group name:", self.room_group_name)
await self.channel_layer.group_add( self.room_group_name, self.channel_name ) print("channel layer:", self.channel_layer) await self.accept()
async def disconnect(self, close_code): """ 与客户端断开连接 :param close_code: :return: """ await self.channel_layer.group_discard( self.room_group_name, self.channel_name )
async def receive(self, text_data): """ 接受客户端websocket发送过来的信息 :param text_data: :return: """ print("test data:", text_data) print("group name:", self.room_group_name)
message = text_data
await self.channel_layer.group_send( self.room_group_name, { 'type': 'chat_message', 'message': message, } )
async def chat_message(self, event): """ 接收room group中传过来的信息,并把信息发送给websocket,发送给前端 :param event: :return: """ message = event['message'] print("event:", event)
await self.send(text_data=json.dumps({ 'message': message }))
|
settings配置
DjangoChannel/asgi.py:
1 2 3 4 5 6 7 8
| import os import django from channels.routing import get_default_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DjangoChannels2.settings") django.setup() application = get_default_application()
|
DjangoChannel/settings.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| INSTALLED_APPS = [ ... 'channels', ]
CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { "hosts": [('127.0.0.1', 6379)], } } }
ASGI_APPLICATION = "DjangoChannel.routing.application"
|
到这里,整个项目就完成了。当访问index.html后,在输入框中输入消息,点击发送按钮后,后端就会接收到消息,并将消息又发回到页面上。