【问题标题】:Is it possible to use ZeroMQ sockets in a Django Channels Consumer?是否可以在 Django Channels Consumer 中使用 ZeroMQ 套接字?
【发布时间】:2020-03-08 23:31:30
【问题描述】:

我有一个爱好项目,那就是建造一艘自动驾驶船。我现在使用 Vuejs 前端和 Django 后端构建了一个 GUI。在这个 GUI 中,我可以在地图上看到船,并向其发送命令。这些命令通过ZeroMQ sockets 发送,效果很好。

我正在使用Django channels 将命令从前端通过 websocket 发送到后端,然后从那里通过 ZeroMQ 套接字发送。我的消费者(效果很好)如下所示:

import zmq
from channels.generic.websocket import WebsocketConsumer
from .tools import get_vehicle_ip_address, get_vehicle_steer_socket

context = zmq.Context()

class SteerConsumer(WebsocketConsumer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.forward_steer_socket = get_vehicle_steer_socket(context, get_vehicle_ip_address())

    def connect(self):
        self.accept()

    def receive(self, text_data):
        print("Passing on the commands from the frontend:", text_data, "to the boat")
        self.forward_steer_socket.send_string(text_data)

除此之外,我还通过 ZeroMQ 套接字从船上接收位置信息,并将其保存到数据库中。我在一个单独的脚本中运行它,前端只是每 2 秒轮询一次后端以获取更新。这是接收船只信息的脚本:

import os
import django
import zmq
os.environ['DJANGO_SETTINGS_MODULE'] = 'server.settings'
django.setup()

# Socket to receive the boat location
context = zmq.Context()
location_socket = context.socket(zmq.SUB)
location_socket.setsockopt(zmq.CONFLATE, True)
location_socket.bind('tcp://*:6001')
location_socket.setsockopt_string(zmq.SUBSCRIBE, '')

while True:
    boat_location = location_socket.recv_json()
    print(boat_location)
    # HERE I STORE THE BOAT LOCATION in the DB

我现在想将这个location_socket 添加到Consumer 以便Consumer 也可以接收ZeroMQ 套接字上的船位置并通过websocket 将其发送到前端。

我当然可以简单地将location_socket 添加到Consumer 的__init__() 方法中,如下所示:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.forward_steer_socket = get_vehicle_steer_socket(context, get_vehicle_ip_address())

    self.location_socket = context.socket(zmq.SUB)
    self.location_socket.setsockopt(zmq.CONFLATE, True)
    self.location_socket.bind('tcp://*:6001')
    self.location_socket.setsockopt_string(zmq.SUBSCRIBE, '')

但我显然不能在Consumer 中包含while True 循环。所以从这里我不知道该怎么做。我实际上不知道这是否可能,因为 Django Channels 似乎是专门为 websockets 制作的。我想我可以开始使用多线程或多处理库,但这对我来说是未知领域。

有人知道是否以及如何在 Django 通道中创建 ZeroMQ 侦听器吗?

【问题讨论】:

    标签: python django websocket zeromq django-channels


    【解决方案1】:

    可以通过https://channels.readthedocs.io/en/latest/topics/channel_layers.html#using-outside-of-consumers直接从您的分离脚本向您的消费者发送消息

    当新客户端在SteerConsumer 内连接到您的消费者时,您将拥有self.channel_name,这对于该客户端来说是唯一的。要将消息发送给该消费者,您只需执行(在您的示例中来自单独的脚本):

    from channels.layers import get_channel_layer
    
    channel_layer = get_channel_layer()
    # "channel_name" should be replaced for the proper name of course
    channel_layer.send("channel_name", {
        "type": "chat.message",
        "text": "Hello there!",
    })
    

    并在您的 SteerConsumer 方法中添加来处理此消息:

    def chat_message(self, event):
        # Handles the "chat.message" event when it's sent to us.
        self.send(text_data=event["text"])
    

    【讨论】:

    • 谢谢。我想这可以工作。不过,它仍然需要我运行两件事:django 和单独的脚本。由于我正在对其进行 dockerizing,因此我想将其最小化为运行一个命令。另外,一般来说,将它保存在一个脚本中并不那么复杂。如果在消费者中真的不可能做到这一点,这将是一个很好的第二选择。今天晚些时候我会测试一下。
    • 我不确定你为什么在这里使用 ZeroMQ。难道不能使用 websockets 直接从你的船连接到后端吗?
    • 我猜是这样,但 zeromq 只是它现在的设计方式。我可以改变它,但是我仍然需要在 websockets 和 mqtt 之间做出决定(这是同事推荐的)。你有使用mqtt的经验吗?这当然是题外话,但我只是想知道。也许你有有趣的见解.. :-)
    猜你喜欢
    • 2022-01-12
    • 2019-06-22
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    • 2011-10-06
    • 2013-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多