前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >django-channels实现群聊

django-channels实现群聊

作者头像
zy010101
发布2021-12-08 16:10:52
1.7K0
发布2021-12-08 16:10:52
举报
文章被收录于专栏:程序员

启用Channels Layer

Layer是一种通信系统。它允许多个消费者实例相互交谈,以及与 Django 的其他部分交谈。借助Layer可以很方便的实现群聊功能。无需我们手动管理websocket连接。

配置channel layer

在settings.py文件中,加入下面的配置,即可在内存中由channels自动维护

代码语言:javascript
复制
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer",
    }
}

这个基于内存的通道层是不能在生产中使用的,因为内存通道层作为一个单独的层在每个进程中运行。这意味着不可能进行跨进程消息传递。在实际生产中,需要使用Redis来作为通道层。(所以,在Django中目前提供websocket支持确实非常麻烦,你自己基于Django3的ASGI实现websocket也很麻烦。)

安装channels_redis

代码语言:javascript
复制
pip3 install channels_redis

配置Redis Layer

代码语言:javascript
复制
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [("127.0.0.1", 6379)],
        },
    },
}

修改consumers.py的内容。

代码语言:javascript
复制
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer

class ChatConsumer(WebsocketConsumer):
    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['group']
        self.room_group_name = 'chat_%s' % self.room_name
        # Join room group
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )

        self.accept()

    def disconnect(self, close_code):
        # Leave room group
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket
    def receive(self, text_data):
        message = text_data
        # Send message to room group
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

    # Receive message from room group
    def chat_message(self, event):
        message = event['message']

        # Send message to WebSocket
        self.send(message)

此处这段代码,是对官方的文档做了一个小小的修改,这里需要对一些东西解释一下。

  • 首先是async_to_sync,这个包装器是将异步操作转为同步操作。这是因为channels layer的所有方法都是异步的。 由此可知,channels应该也是基于事件循环机制的。如果想在Python中使用异步,那么就需要将方法变成协程函数。此处我们仍旧使用了普通函数,因此需要async_to_sync来将异步操作转换为同步操作。
  • scope,这个东西是asgi规范规定的,scope具体的内容可以看scope,这里的url_route是channels自己添加的部分,URLRouter会将捕获的组从URL放入scope[“url_route”]中的kwargs,然后我们根据re_path()中的分组名来获取值。
  • self.room_group_name是channels layer的组名,我们是根据url参数来直接构造了一个组名。组名只能包含字母、数字、_和句点(.)。
  • self.channel_layer.group_add有两个参数,分别是组名和当前websocket连接的名称,作用是将当前的连接加入到名为xxx的组中。
  • self.channel_name是随机生成的,我们可以直接使用。
  • self.channel_layer.group_discard,的作用是将self.channel_name从组self.room_group_name中删除并断开连接。
  • channel_layer.group_send作用是像向组xx发送事件,这里是向self.room_group_name组发送事件。事件有一个特殊的键type,对应于在接收事件的消费者上调用的方法的名称。本例中,就是chat_message这个方法,你需要在chat_message方法中调用self.send()方法来发送。

异步实现

代码语言:javascript
复制
from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['group']
        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):
        message = text_data
        # 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(message)

需要注意,异步需要继承自AsyncWebsocketConsumer类,然后所有的IO操作都是异步IO,类中的方法都是协程。但是需要注意,Django的模型和

参考文档:Channels

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/12/07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 启用Channels Layer
    • 配置channel layer
      • 异步实现
      相关产品与服务
      云数据库 Redis®
      腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档