无法通过group_send

问题描述

我想使用Django频道通过频道发送消息。这就是我的做法。

我首先创建一个消费者。我能够回显收到的消息。但是,无法将消息发送到特定的频道/组。

class Consumer(AsyncJsonWebsocketConsumer):
    """Consumer."""

    def _get_connection_id(self):
        return ''.join(e for e in self.channel_name if e.isalnum())

    async def connect(self):
        scope = self.scope
        user_id = str(scope['user'].user_id)
        connection_id = self._get_connection_id()
        # Adding connection to DB.
        obj = UserConnection.add(connection_id=connection_id,user_id=user_id)

        # Accept the connection
        await self.accept()

        # Adding current to group.
        await self.channel_layer.group_add(
            user_id,connection_id,)

    async def disconnect(self,close_code):
        """Remove the connection and decrement connection_count in DB."""
        connection_id = self._get_connection_id()
        user_id = str(self.scope['user'].user_id)

        UserConnection.drop(connection_id=connection_id)

        # Dropping from group.
        await self.channel_layer.group_discard(
            user_id,)

    async def receive_json(self,data,**kwargs):
        """Receive messages over socket."""
        resp = data
        # I'm able to echo back the received message after some processing.
        await self.send(json.dumps(resp,default=str))


# This does not works.
def send_to_connection(connection_id,data):
    """Send the data to the connected socket id."""
    return get_channel_layer().group_send(connection_id,data)

现在,当我尝试发送消息时,连接的套接字没有收到消息。

>>> connection_id = UserConnection.objects.get(user_id=user_id).connection_id
>>> send_to_connection(connection_id,{'a':1})
# returns <coroutine object RedisChannelLayer.group_send at 0x109576d40>

代码有什么问题?

解决方法

关于Channel层的工作方式存在一些误解。让我尝试清除它。当客户端连接到Channels服务器时,将为该客户端创建使用者实例或通道。如果您将频道添加到组中,则Django频道会将该信息存储在频道层中。如果要向组中的所有客户端发送消息,请先将其通过通道层发送到其连接/通道,然后通道将向下游发送消息给已连接的客户端。

因此,在您的情况下,当您调用group_send时,它没有将消息发送到客户端应用程序,因为它不具有有关Websocket连接的信息,但是没有客户端应用程序的使用者实例。然后,该消费者实例需要提取消息并将其转发给客户端。

按照文档中的示例,这是您需要做的:

    async def receive_json(self,data,**kwargs):
        """Receive messages over socket."""
        resp = data
        # I'm able to echo back the received message after some processing.
        await self.send(json.dumps(resp,default=str))
   
   # catches group messages from channel layer and forwards downstream to client 
   async def forward_group_message(self,event):
        await self.send(json.dumps(event['data'],default=str))

# Sends message to all channels in a group cia the channel layer
def send_to_connection(connection_id,data):
    """Send the data to the connected socket id."""
    return get_channel_layer().group_send(
        connection_id,{"type": "forward_group_message","data": data}
    )

注意,如果您要发送到频道层,请按type键。这就是Django Channel如何知道使用者将通道层事件路由到哪个方法/处理程序。您还可以使用文档中使用的点符号,并且Django Channels仍会找到处理程序。因此,您可以使用"type": "forward.group.message"