我目前正在尝试使用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 "";
}
按预期方式推送数据
基于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
在控制台中报告的内容:
Netstat输出:
注意:当我同时终止Metatrader推送脚本和python脚本时,端口仍在netstats中标记为“已侦听”。当我在两个实例中将端口都更改为32225(或任何其他端口)并重新运行它们时,我再次遇到相同的错误。如果我第一次运行pull实例,我会在原子script
中弹出一个沙漏,然后再运行MT4 push实例时,在pull端没有任何反应。然后,当我重新运行pull实例时,我再次遇到相同的错误。
更新:
后台的python.exe
实例占用了端口。我关闭了python执行程序,并再次释放了端口。现在,当我运行我的请求实例时,会收到以下控制台反馈:
1。)
2。)
然后我运行可以正常工作的push实例。
3。)
pull实例仍然显示沙漏,并且不会在控制台中打印任何数据:
4。)
当我重新运行pull实例时,它会引发错误正在使用的地址,这现在很有意义,因为Python仍在后台使用该端口。
但是为什么没有在提取侧打印任何数据?为了能够“抓取”推送的数据,我是否必须更改提取客户端代码?
答案 0 :(得分:1)
问题出在您的PUSH
代码上,
extern string HOSTNAME = "*";
虽然您可以合法地在*
URL中将bind
用作主机名组件(在这种情况下,它的意思是“监听所有地址”),但在{{ 1}}通话:您必须提供有效的主机名或IP地址。
如果要将代码修改为:
connect
它可能会按预期工作。
这是我用来测试您的extern string HOSTNAME = "localhost";
代码的简单Python PUSH
客户端;如果您运行此程序并运行PULL
代码(如您的问题中所述),则全部正常:
PULL