ps:使用windows+djang + asgi +channels
1、在总url同级目录下创建routing.py文件
from django.urls import re_path
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from projects import consumers # consumers.py文件所在位置
application = ProtocolTypeRouter({
"websocket": AuthMiddlewareStack(
URLRouter([
re_path(r"socket_once/**/$", consumers.ChatConsumer.as_asgi()),
])
)
})
2、在总url同级目录下创建asgi.py文件
import os
import django
# 初始化django环境
os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'web_rf.setting.dev')
django.setup()
from channels.routing import get_default_application
# 配合同级目录下的routing.py使用
application = get_default_application()
3、项目目录下使用consumers.py(和view.py同级)
import os
from channels.generic.websocket import WebsocketConsumer
from django_redis import get_redis_connection
from web_rf.utils.logger import logger
# 使用组时,组列表
consumer_object_list = []
class ChatConsumer(WebsocketConsumer):
"""socket"""
result = None
# 使用redis存储channel__name信息
redis_conn = get_redis_connection('socket_number')
socket = 'socket_' + '0'
def websocket_connect(self, message):
"""客户端请求建立连接,自动触发"""
# 获取用户信息
user_id = self.scope['url_route']['kwargs']['user_id']
# socket的id
# log_id = self.scope['url_route']['kwargs']['id']
# 和客户端socket编号一起保存到redis
self.socket_key = "socket_" + 'user_id'
self.redis_conn.set(self.socket_key, self.channel_name)
# 建立连接,并且自动维护每一个客户端
self.accept()
# 这里直接使用
# self.send("发送信息", selfe.channel_name)
# 其他功能测试
# channel_layer = get_channel_layer()
# self.result = ceshi.delay(log_id, selfe.channel_name)
# 将连接在列表中存储一份
# consumer_object_list.append(self)
# 获取组名
# self.group_name = self.scope['url_route']['kwargs']['group_name']
# 添加组信息
# self.channel_layer.group_add(self.group_name, self.channel_name)
# 将连接添加至连接组信息chats中
# try:
# ChatConsumer.chats[self.group_name].add(self)
# except:
# ChatConsumer.chats[self.group_name] = set([self])
# 创建完成后调用
# self.accept
def websocket_receive(self, message):
"""客户端发送数据过来,自动触发"""
text = message.get("text") # 接收客户端发送的消息
# 给客户端发送信息,这里是单独发送
message_send = {"type": 'websocket.receive', "message": 'hello world'}
message_send = json.dumps(message_send)
self.send(text_data=message_send)
# 根据组给所有链接对象发送信息
# for obj in consumer_object_list:
# obj.send(text_data=text)
def websocket_celery(self, message):
"""celery发送过来的数据, 自动触发"""
text = json.dumps(message) # 转换为json格式的字符串
# 给客户的发送信息
self.send(text_data=text)
# 根据组给所有链接对象发送信息
# for obj in consumer_object_list:
# obj.send(text_data=text)
def websocket_disconnect(self, message):
"""客户端断开链接后,自动触发"""
# 客户端断开链接,将当前客户端对象移除
# consumer_object_list.remove(self)
# raise StopConsumer()
# 链接关闭时调用
# 将关闭的连接从群组中移除
# self.channel_layer.group_discard(self.group_name, self.channel_name)
# 将该客户端移除出组连接信息
# ChatConsumer.chats[self.group_name].remove(self)
# 清除celery任务
# self.result.revoke()
# self.close()
4、我这里是直接在celery中使用的,视图中使用同理
from __future__ import absolute_import, unicode_literals # 绝对引用新特性
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
from django_redis import get_redis_connection
# 获取channle_name信息
redis_conn = get_redis_connection("socket_number")
channels_name = redis_conn.get('socket_' + 'user_id')
# socket连接
channels_layer = get_channel_layer()
# redis取出的是二进制数据,解码
channels_name = channels_name .decode("utf-8")
async_to_sync(channels_layer.send)(
channels_name,
{
# 这里的websocekt.celery是consumers.py中的websocekt_celery方法,需要写成这样
"type": "websocket.celery",
'message': "发送的信息",
'msg_type': '自定义的一些key-value'
}
)