简体   繁体   English

是否可以在 Django 通道消费者中使用 ZeroMQ sockets?

[英]Is it possible to use ZeroMQ sockets in a Django Channels Consumer?

I've got a hobby project of building an autonomous boat.我有一个爱好项目是建造一艘自动驾驶船。 I now built a GUI using a Vuejs frontend and a Django backend.我现在使用 Vuejs 前端和Django后端构建了一个 GUI。 In this GUI I can see the boat on a map, and send commands to it.在这个 GUI 中,我可以看到 map 上的船,并向其发送命令。 Those commands are sent over ZeroMQ sockets which works great.这些命令通过ZeroMQ sockets发送,效果很好。

I'm using Django channels to send the commands from the frontend over a websocket to the backend and from there I send it on over the ZeroMQ socket.我正在使用Django 通道将命令从前端通过 websocket 发送到后端,然后从那里通过 ZeroMQ 套接字发送。 My consumer (which works great) looks as follows:我的消费者(效果很好)如下所示:

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)

Next to this I also receive location information from the boat over a ZeroMQ socket which I save to the database.在此旁边,我还通过 ZeroMQ 套接字从船上接收位置信息,并将其保存到数据库中。 I'm running this in a separate script and the frontend simply polls the backend every 2 seconds for updates.我在一个单独的脚本中运行它,前端只是每 2 秒轮询一次后端以进行更新。 Here's the script receiving the boat info:这是接收船只信息的脚本:

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

I would now like to add this location_socket to the Consumer so that the Consumer can also receive the boat location on the ZeroMQ socket and send it to the frontend over the websocket.我现在想将此location_socket添加到Consumer ,以便Consumer也可以接收 ZeroMQ 套接字上的船位置,并通过 websocket 将其发送到前端。

I can of course simply add the location_socket to the Consumer its __init__() method as follows:我当然可以简单地将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, '')

But I obviously cannot include the while True loop in the Consumer .但我显然不能在Consumer中包含while True循环。 So from here I'm not sure what to do.所以从这里我不知道该怎么做。 I actually don't know whether this is even possible, since Django Channels seems to specifically been made for websockets.我实际上不知道这是否可能,因为 Django 通道似乎是专门为 websockets 制作的。 I guess I could start using multithreading or multiprocessing libraries, but that is uncharted territory for me.我想我可以开始使用多线程或多处理库,但这对我来说是未知领域。

Does anybody know whether and how it is possible to make a ZeroMQ listener in a Django Channel?有谁知道是否以及如何在 Django 通道中创建 ZeroMQ 侦听器?

It is possible to send message to your consumer directly from your separated script via: https://channels.readthedocs.io/en/latest/topics/channel_layers.html#using-outside-of-consumers可以通过以下方式直接从您的分离脚本向您的消费者发送消息: https://channels.readthedocs.io/en/latest/topics/channel_layers.html#using-outside-of-consumers

When the new client connects to your consumer inside SteerConsumer you have self.channel_name which is unique for that client.当新客户端连接到SteerConsumer内的消费者时,您将拥有self.channel_name ,该名称对于该客户端是唯一的。 To send message to that consumer you just have to execute (in your example from separated script):要将消息发送给该消费者,您只需执行(在您的示例中来自单独的脚本):

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!",
})

and add inside your SteerConsumer method to handle this message:并在您的SteerConsumer方法中添加以处理此消息:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM