可以在Django Channels Consumer中使用ZeroMQ套接字吗?

时间:2019-11-13 07:52:22

标签: python django websocket zeromq django-channels

我有一个业余爱好,那就是建造自动船。我现在使用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, '')

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

有人知道在Django频道中是否以及如何制作ZeroMQ侦听器吗?

1 个答案:

答案 0 :(得分:2)

可以通过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"])