簡體   English   中英

如何使用 django 通道和 websockets 從服務器的任何位置向客戶端發送事件

[英]How to send event to client from any place of server using django channels and websockets

現在我正在使用 django 和 angular 構建網站,並且我想在客戶端和服務器之間添加 websocket 通信。 我按照 django 頻道文檔的說明進行操作。( https://channels.readthedocs.io/ )我想從 django 服務器代碼的任何位置發送任何事件。 但是當多個用戶通過套接字連接時,服務器發送的數據總是發送到最后一個連接的用戶。 這就是我所做的。 首先在consumers.py中,我定義了我的ChatConsumer class,並添加了一個名為“tweet_send”的新處理程序function

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()
    ...

    # here's what I added a new tweet send handler
    async def tweet_send(self, event):
        content = event['content']
        content["group_name"] = self.room_group_name

        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            "type": "MESSAGE",
            "data": content
        }))

在 django 服務器端(在 serializers.py 中)的某處,當創建新推文時,我使用 django.channel_layer 向所有用戶發送新推文數據

...
def create(self, validated_data):
    ...
    new_tweet.save()

    # send message via channels
    channel_layer = get_channel_layer()
    all_users = list(Member.objects.filter(is_active = True).values_list('id', flat = True))
    for user_id in all_users:
        async_to_sync(channel_layer.group_send)(
            "chat_{}".format(user_id),            # this is the group name of group name of individual users.
            { "type": "chat_message", "message": "tweet created" }
        )

並在 Angular websocket 服務中

init(userID: number): void{
  if(this.ws){
    this.ws.close();
  }

  this.ws = new WebSocket(`${environment.WEBSOCKET_URL}/chat/${userID}/`);
  this.ws.onopen = () => {
    this.currentWebSocketSubject.subscribe(data => {
      if (data) {
        this.ws?.send(JSON.stringify(data));
      }
    });
  };

  this.ws.onmessage = (event) => {
    console.log("message arrived");
    console.log(event);
    if (event.data) {
      const tempData: WS = JSON.parse(event.data) as WS;
      switch (tempData.type) {
        case 'MESSAGE':
          console.log("message arrived");
          console.log(tempData);
          if (tempData.data) {
            this.unreadMessages++;
            this.messageSubject.next(tempData);
          }
          break;

      }
    }
  };
}

當我測試這些代碼時,我使用了兩個客戶端,兩個客戶端登錄,並通過 websockets 成功連接到 django 服務器。 When I create a tweet, django server sends event to every channel using channel_layer.group_send function, and in ChatConsumer class the added "tweet_send" function sends the event to the user. 這些事件分別針對不同的用戶。 但它們都被發送給最后連接 websocket 的用戶。 我不知道為什么。 請幫我。

現在,我正在使用django和angular創建一個網站,並且我想在客戶端和服務器之間添加websocket通信。 我遵循了django通道文檔的說明。( https://channels.readthedocs.io/ )我想從django服務器代碼的任何位置發送任何事件。 但是,當多個用戶通過套接字連接時,從服務器發送的數據將始終流向最后一個連接的用戶。 這就是我所做的。 首先,在consumers.py中,我如下定義了ChatConsumer類,並添加了一個名為“ tweet_send”的新處理函數。

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()
    ...

    # here's what I added a new tweet send handler
    async def tweet_send(self, event):
        content = event['content']
        content["group_name"] = self.room_group_name

        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            "type": "MESSAGE",
            "data": content
        }))

在django服務器端的某個位置(在serializers.py中),當創建新的tweet時,我使用django.channel_layer將新的tweet數據發送給所有用戶

...
def create(self, validated_data):
    ...
    new_tweet.save()

    # send message via channels
    channel_layer = get_channel_layer()
    all_users = list(Member.objects.filter(is_active = True).values_list('id', flat = True))
    for user_id in all_users:
        async_to_sync(channel_layer.group_send)(
            "chat_{}".format(user_id),            # this is the group name of group name of individual users.
            { "type": "chat_message", "message": "tweet created" }
        )

並在Angular Websocket服務中

init(userID: number): void{
  if(this.ws){
    this.ws.close();
  }

  this.ws = new WebSocket(`${environment.WEBSOCKET_URL}/chat/${userID}/`);
  this.ws.onopen = () => {
    this.currentWebSocketSubject.subscribe(data => {
      if (data) {
        this.ws?.send(JSON.stringify(data));
      }
    });
  };

  this.ws.onmessage = (event) => {
    console.log("message arrived");
    console.log(event);
    if (event.data) {
      const tempData: WS = JSON.parse(event.data) as WS;
      switch (tempData.type) {
        case 'MESSAGE':
          console.log("message arrived");
          console.log(tempData);
          if (tempData.data) {
            this.unreadMessages++;
            this.messageSubject.next(tempData);
          }
          break;

      }
    }
  };
}

當測試這些代碼時,我使用了兩個客戶端,兩個客戶端登錄,並成功通過websockets連接到django服務器。 創建推文時,django服務器使用channel_layer.group_send函數將事件發送到每個通道,並且在ChatConsumer類中添加的“ tweet_send”函數將事件發送給用戶。 這些事件分別針對不同的用戶。 但是它們都被發送給了最后一個連接了websocket的用戶。 我不知道為什么請幫我。

我可以看到這個問題已經在這里很久了。 您的代碼存在一個問題,該問題是您的使用者 (tweet_send) 中的推文發送處理程序與您從您的 serializers.py 發送到組的消息類型不匹配。

因此,要解決此問題,您必須重命名推文發送處理程序方法以匹配您發送到組的消息類型,在本例中為chat_message 因此,您的推文發送處理程序變為:

# tweet send handler
async def chat_message(self, event):
    content = event['content']
    content["group_name"] = self.room_group_name

    # Send message to WebSocket
    await self.send(text_data=json.dumps({
        "type": "MESSAGE",
        "data": content
    }))

我希望這會有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM