Skip to main content
 首页 » 编程设计

python之使用 Django Channels 向所有连接的客户端发送信息

2024年10月01日39yyy_WW

我正在创建一个系统,其中 Twitter Live Streaming API 通过给定的关键字获取实时推文数据流。每当推文出现时,我都想通过 WebSockets(使用 Django Channels)将新数据发送到所有连接的客户端。这是我目前的程序:

  1. Twitter 直播代码在获取新数据时调用 consumers.py 中的 initiateHandshake() 函数
  2. Django channel 向所有客户端发送文本“握手”
  3. 客户端收到握手消息并发回消息
  4. websocket.recieve 函数获取此消息,并根据存储在客户端连接 session 中的过滤器信息,发回所需的数据(这就是为什么需要握手 - 因为每个客户端都有自己的过滤器正在连接 session 中)

现在,问题是 initiateHandshake() 中的“握手”消息没有发送。为什么会这样,我该如何解决?太感谢了!我的代码如下。

WebSockets 正常运行(如果客户端发送消息,我可以使用 reply_channel 来回复它 - 一切正常)

路由.py

from channels.routing import route 
from tweetrunner.consumers import * 
 
channel_routing = [ 
    route("websocket.connect", ws_connect), 
    route("websocket.receive", ws_message), 
    route("websocket.disconnect", ws_disconnect), 
] 

消费者.py

# In consumers.py 
from channels import Group, Channel 
from channels.sessions import channel_session 
from .models import InputTweet 
from django.shortcuts import render 
 
# Outside world connection 
def initiateHandshake(): 
    Group("table").send({"text": "handshake"}) 
 
 
# Connected to websocket.connect 
@channel_session 
def ws_connect(message): 
    # Accept connection 
    message.reply_channel.send({"accept": True}) 
    message.channel_session["sort"] = "none" 
    # Add to group 
    Group("table").add(message.reply_channel) 
 
 
# Connected to websocket.receive 
@channel_session 
def ws_message(message): 
    definition = message.content['text'][:1] 
 
    if definition == "1": 
        emotion = message.content['text'][1:] 
        message.channel_session["sort"] = message.content['text'][1:] 
 
        sendback = "" 
 
        if emotion == 'none': 
            given_tweets = InputTweet.objects.all() 
            given_tweets = given_tweets[(len(given_tweets) - 1250):] 
            print("before render") 
            sendback = render(None, 'tweetrunner/get_table_update.html', {'given_tweets': given_tweets}) 
            print("rendered") 
        else: 
            given_tweets = InputTweet.objects.filter(emotion__startswith=emotion).order_by('score') 
            given_tweets = given_tweets[(len(given_tweets) - 1250):] 
            sendback = render(None, 'tweetrunner/get_table_update.html', {'given_tweets': given_tweets}) 
 
        print("about to send") 
        message.reply_channel.send({ 
            "text": sendback.content.decode('utf-8'), 
        }) 
        print("sent -- END CONNECTION LOGS") 
 
    elif definition == "3": 
        print("Keep alive!") 
 
    else: 
 
        emotion = message.channel_session["sort"] 
 
        sendback = "" 
 
        print("entered 2") 
 
        if emotion == 'none': 
            given_tweets = InputTweet.objects.all() 
            given_tweets = given_tweets[(len(given_tweets) - 1250):] 
            print("before render") 
            sendback = render(None, 'tweetrunner/get_table_update.html', {'given_tweets': given_tweets}) 
            print("rendered") 
        else: 
            given_tweets = InputTweet.objects.filter(emotion__startswith=emotion).order_by('score')      
            given_tweets = given_tweets[(len(given_tweets) - 1250):] 
            sendback = render(None, 'tweetrunner/get_table_update.html', {'given_tweets': given_tweets}) 
 
        print("about to send") 
 
        #content = sendback.read() 
 
        message.reply_channel.send({ 
            "text": sendback.content.decode('utf-8'), 
        }) 
 
        print("sent -- END CONNECTION LOGS") 
 
 
# Connected to websocket.disconnect 
@channel_session 
def ws_disconnect(message): 
    Group("table").discard(message.reply_channel) 

我的代码不在任何 django 应用程序中,正在像这样初始化 django(我可以访问数据库并使用 django 调用,所以它可以工作):

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "analyticsui.settings") 
 
import django 
django.setup() 

客户端上的 JavaScript:

socket = new WebSocket("ws://" + window.location.host + "/"); 
 
socket.onmessage = function(e) { 
alert("Got message: " + e.data) 
    if (e.data == "handshake") { 
        socket.send("2handshake"); 
        alert("sent"); 
    } else { 
        document.getElementById("tweetTable").innerHTML = e.data; 
        $('.tooltiphere').tooltip('remove'); 
        $('.tooltiphere').tooltip({delay: 10}); 
    } 
} 

请您参考如下方法:

initiateHandshake()当您使用 In-memory Channel 层时,不会发送任何消息。

From the doc: In-Memory layer does not support cross-process communication

请特别使用其他 channel 层类型<a href="https://channels.readthedocs.io/en/stable/backends.html#redis" rel="noreferrer noopener nofollow">Redis channel layer</a> .一切都会按预期进行。