无法使用zeroMQ“正在使用的地址”在拉式插座上接收数据-错误

时间:2019-12-01 11:09:40

标签: python sockets zeromq

我目前正在尝试使用zeroMQ建立一个普通的推挽套接字体系结构,而Metatrader 4(MQL)充当publisher,而我的Python后端充当consumer

我每秒从Metatrader 4终端推送数据,效果很好。但是,我在接收拉式插座上的数据时遇到困难。一旦我尝试将数据从导线中拉出,原子script包就会引发错误address already in use

在开发过程中,我在本地计算机上同时运行MT 4终端和Python脚本。

Metatrader 4:

extern string PROJECT_NAME = "Dashex.Feeder";
extern string ZEROMQ_PROTOCOL = "tcp";
extern string HOSTNAME = "*";
extern int PUSH_PORT = 32220;

extern string t0 = "--- Feeder Parameters ---";
input string DID = "insert your DID here";
extern string t1 = "--- ZeroMQ Configuration ---";
extern bool Publish_MarketData = false;

// ZeroMQ environment //

// CREATE ZeroMQ Context
Context context(PROJECT_NAME);

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

string Publish_Symbols[7] = {
   "EURUSD","GBPUSD","USDJPY","USDCAD","AUDUSD","NZDUSD","USDCHF"
};

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

int OnInit()
  {
//---

   EventSetTimer(1);     // Set Millisecond Timer to get client socket input

   context.setBlocky(false);

   // Send responses to PULL_PORT that client is listening on.
   Print("[PUSH] Connecting MT4 Server to Socket 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);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---

   Print("[PUSH] Disconnecting MT4 Server from Socket 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();
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTimer()
{
   /*
      Use this OnTimer() function to send market data to consumer.
   */
   if(!IsStopped() && Publish_MarketData == true)
   {
      for(int s = 0; s < ArraySize(Publish_Symbols); s++)
      {
         // Python clients can subscribe to a price feed by setting
         // socket options to the symbol name. For example:

         string _tick = GetBidAsk(Publish_Symbols[s]);
         Print("Sending " + Publish_Symbols[s] + " " + _tick + " to PUSH Socket");
         ZmqMsg reply(StringFormat("%s %s", Publish_Symbols[s], _tick));
         pushSocket.send(reply, true);
      }
   }
}
//+------------------------------------------------------------------+

string GetBidAsk(string symbol) {

   MqlTick last_tick;

   if(SymbolInfoTick(symbol,last_tick))
   {
       return(StringFormat("%f;%f", last_tick.bid, last_tick.ask));
   }

   // Default
   return "";
}

按预期方式推送数据

enter image description here

基于Python的拉式插座:

import zmq
import time

context = zmq.Context()
zmq_socket = context.socket(zmq.PULL)
zmq_socket.bind("tcp://*:32220")
time.sleep(1)

while True:
    result = zmq_socket.recv()
    print(result)
    time.sleep(1)

这是script在控制台中报告的内容:

enter image description here

Netstat输出:

enter image description here

注意:当我同时终止Metatrader推送脚本和python脚本时,端口仍在netstats中标记为“已侦听”。当我在两个实例中将端口都更改为32225(或任何其他端口)并重新运行它们时,我再次遇到相同的错误。如果我第一次运行pull实例,我会在原子script中弹出一个沙漏,然后再运行MT4 push实例时,在pull端没有任何反应。然后,当我重新运行pull实例时,我再次遇到相同的错误。

更新

后台的python.exe实例占用了端口。我关闭了python执行程序,并再次释放了端口。现在,当我运行我的请求实例时,会收到以下控制台反馈:

1。)

enter image description here

2。)

然后我运行可以正常工作的push实例。

3。)

pull实例仍然显示沙漏,并且不会在控制台中打印任何数据:

enter image description here

4。)

当我重新运行pull实例时,它会引发错误正在使用的地址,这现在很有意义,因为Python仍在后台使用该端口。

但是为什么没有在提取侧打印任何数据?为了能够“抓取”推送的数据,我是否必须更改提取客户端代码?

1 个答案:

答案 0 :(得分:1)

问题出在您的PUSH代码上,

extern string HOSTNAME = "*";

虽然您可以合法地在* URL中将bind用作主机名组件(在这种情况下,它的意思是“监听所有地址”),但在{{ 1}}通话:您必须提供有效的主机名或IP地址。

如果要将代码修改为:

connect

它可能会按预期工作。

这是我用来测试您的extern string HOSTNAME = "localhost"; 代码的简单Python PUSH客户端;如果您运行此程序并运行PULL代码(如您的问题中所述),则全部正常:

PULL