Как структурировать простой односторонний шаблон ZeroMQ Push-Pull с N-производителями (подключение) и 1-потребителем (привязка) — MT4 для Python

Несколько пользователей будут передавать данные из Metatrader 4 в серверную часть Python. Таким образом, количество запущенных экземпляров Metatrader 4 (= производителей) является динамическим. Каждый экземпляр MT4 будет работать на локальных машинах пользователей, создавать свои собственные zmq.context и zmq.socket (push). Таким образом, мы получаем в основном структуру N-to-1:

|-------------------Производитель1-----Производитель2-----Производитель3-----Производитель4-----ПроизводительX< /strong>--------------------------------- --|---------------------------------|----------------|---------- ----------------------|---------------------------------|-------- --------
...................................... .|-----------------Потребитель/Бэкэнд------------------|......... .................................

При этом потребитель будет работать 24/7 и ждать данных от любого производителя. если есть 160 пользователей онлайн, чтобы использовать услугу, потребитель должен будет обрабатывать ввод данных с этих 160 узлов и т. д. и т. д. Порядок полученных сообщений не имеет значения, и если некоторые сообщения время от времени пропадают, это также не имеет значения.

введите здесь описание изображения

Текущее состояние:
Прямо сейчас мой код (см. ниже) работает очень хорошо, используя один экземпляр Metatrader 4 на моем собственном локальном компьютере. Но что произойдет, если есть X экземпляров MT4, и все они имеют свои собственные контексты zmq и push-сокеты в локальном экземпляре метатрейдера 4 для отправки данных? Будет ли он работать так, как задумано?

Конец производителя кода (экземпляр Metatrader 4), который каждый пользователь будет запускать на своем локальном компьютере:

extern string ZEROMQ_PROTOCOL = "tcp";
extern string HOSTNAME = "localhost";
extern int PUSH_PORT = 32225;

// CREATE ZeroMQ Context
Context context(PROJECT_NAME);

// CREATE ZMQ_PUSH SOCKET
Socket pushSocket(context, ZMQ_PUSH);

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

int OnInit()
  {

//---

   EventSetTimer(1);     // Set Second Timer as push intervall

   context.setBlocky(false);

   // Send data to PULL_PORT that consumer is listening to.
   Print("[PUSH] Connecting MT4 Dashex Feeder to Dashboard on Port " + IntegerToString(PUSH_PORT) + "..");
   pushSocket.connect(StringFormat("%s://%s:%d", ZEROMQ_PROTOCOL, HOSTNAME, PUSH_PORT));

   pushSocket.setSendHighWaterMark(1);
   pushSocket.setLinger(0);   

   return(INIT_SUCCEEDED);
  }

//---

void OnDeinit(const int reason)
{

//---

   Print("[PUSH] Disconnecting MT4 Dashex Feeder on Port " + IntegerToString(PUSH_PORT) + "..");
   pushSocket.disconnect(StringFormat("%s://%s:%d", ZEROMQ_PROTOCOL, HOSTNAME, PUSH_PORT));

   // Shutdown ZeroMQ Context
   context.shutdown();
   context.destroy(0);

   EventKillTimer();
}

[...]

pushSocket.send(StringFormat("%s", account_info, true));

Потребитель серверной части Python:

# create zeroMQ Pull Socket to fetch data out of the wire
context = zmq.Context()
zmq_socket = context.socket(zmq.PULL)
zmq_socket.bind("tcp://*:32225")
time.sleep(1)

while True:
    # check 24/7 for available data in the pull socket
    try:
        [...]

Вопросы:

1.) Текущий код создает новый контекст и сокет для каждого экземпляра метатрейдера 4, работающего на локальном компьютере пользователя, и снова закрывает их после закрытия MT4. Могут ли несколько экземпляров MT4/push-сокетов одновременно отправлять данные одному и тому же потребителю? (это мой желаемый результат)

2.) Кроме того, может ли каждый экземпляр терминала использовать одни и те же порты сокетов или каждому экземпляру терминала нужен уникальный порт?

3.) Должен ли я использовать другой шаблон?

Заранее большое спасибо за ваши мысли и вклад.


person Jonas    schedule 11.12.2019    source источник


Ответы (1)


  1. Вам нужно поделиться контекстом только в том случае, если вы используете inproc транспорт. Поскольку вы используете tcp, он будет работать так, как вы ожидаете.
  2. Терминалы будут connect() с портом, указанным бэкендами Python bind(). Так что да, все терминалы будут подключаться к порту 32225, как указано в вашем коде.
  3. Шаблон push/pull кажется хорошим выбором и должен работать нормально. Если вас беспокоят накладные расходы (много соединений) на вашем бэкэнде python, вы можете разместить прокси-процесс zeromq (PULL/PUSH) между терминалами и бэкэндом.
person James Harvey    schedule 12.12.2019