当两个php在同一服务器上运行时,以下pubsub php正常工作。但是,它们在不同的服务器上运行时不起作用。
(local)client.php <--> (local)server.php (with sleeptime 300) <= OK
(local)client.php <--> (remote)server.php (with sleeptime 300) <= NG
我把睡眠时间从300改为30.确实有效。
(local)client.php <--> (remote)server.php (with sleeptime 30) <= OK
我认为套接字已关闭或仅在远程访问期间发生了某些事情。我该如何解决?我想检测关闭的套接字并重新连接。或者我想在可能的情况下更改超时设置。
server.php
<?php
$context = new ZMQContext();
$publisher = new ZMQSocket($context, ZMQ::SOCKET_PUB);
$publisher->bind("tcp://*:5563");
while (true) {
sleep (300);
$publisher->send("A", ZMQ::MODE_SNDMORE);
$publisher->send("We don't want to see this");
$publisher->send("B", ZMQ::MODE_SNDMORE);
$publisher->send("We would like to see this");
}
client.php
<?php
$context = new ZMQContext();
$subscriber = new ZMQSocket($context, ZMQ::SOCKET_SUB);
$subscriber->connect("tcp://localhost:5563"); // This is the setting for local server.php. I changed it for server.php at remote.php
$subscriber->setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, "B");
while (true) {
$address = $subscriber->recv();
$contents = $subscriber->recv();
printf ("[%s] %s%s", $address, $contents, PHP_EOL);
我使用的是libzmq,php-zmq。 ZMQ :: LIBZMQ_VER是4.2.1。 PHP是第5版。
我不确定,但服务器设置(ubuntu16 LTS)可能是原因。
答案 0 :(得分:2)
我在PHP中使用ZeroMQ进行时间敏感的实时信令。首先,一些理论:互联网工程任务组(IETF)Request for Comments (RFC) 793和RFC 1122指定TCP。在这种情况下,感兴趣的属性是用户超时。用户超时最好在RFC 5482中解释,这是一个实现在应用程序之间传递用户超时设置标准的提案:
&#34;传输控制协议(TCP)规范[RFC0793]定义了本地,每个连接&#34;用户超时&#34;参数 指定传输数据可能保留的最长时间 TCP之前未确认将强行关闭相应的 连接。应用程序可以使用OPEN设置和更改此参数 和发送电话。如果端到端连接中断持续时间更长 比用户超时,发件人将不会收到任何确认 任何传输尝试,包括保持活动,它将关闭 发生用户超时时的TCP连接...
在没有应用程序指定的用户超时的情况下,TCP 规范[RFC0793]定义默认用户超时为5分钟。 主机要求RFC [RFC1122]通过改进此定义 引入两个阈值R1和R2(R2> R1),控制 单个段的重新传输尝试次数。它表明 当达到R1时,TCP应该通知应用程序 段,并在达到R2时关闭连接。 [RFC1122]也 定义R1(3次重传)和R2(100次)的推荐值 秒),注意到SYN段的R2应该至少为3 分钟&#34;
服务器和客户端之间可能存在大量设备;你不太可能控制所有这些(当然除非LAN)。由于目前没有就应用程序和网关的超时设置达成一致的标准;和防火墙are reported to close connections,最好发送&#39;保持活力&#39;定期数据。此外,许多其他问题可能会破坏连接,同样,应用程序可能会失败。因此,保持活动的心跳实现有助于创建一个强大的应用程序,使连接保持打开状态并及时发现问题。
我通常使用1到5秒的心跳间隔,具体取决于应用程序。如果信令关闭(例如,回退到AJAX轮询,警告用户,重新启动脚本等),客户端会计算错过的心跳并相应地做出响应。请记住,发布者 - 订阅者消息不会排队。如果用户错过了它,它会错过它。如果您希望服务器能够确认收据和客户端连接状态,则需要其他通信过程。如果客户端在任何时间内停机,您无法确定是否收到了所有消息。 ZeroMQ Guide has substantial discussion about heartbeating和强大的应用程序设计。
&#34; Heartbeating解决了知道同伴是否还活着的问题 死。这不是ZeroMQ特有的问题。 TCP有很长的超时时间 (30分钟左右),这意味着无法知道 一个同伴是否已经死亡,被断开连接,或者周末去了 布拉格有一箱伏特加,一个红头发和一个大笔费用帐户。&#34;
好的,这是使用您的代码的代码示例:
<强> Server.php 强>
<?php
$context = new ZMQContext();
$publisher = new ZMQSocket($context, ZMQ::SOCKET_PUB);
$publisher->bind("tcp://*:5563");
$i = 0; // Iteration counter to trigger message
while (true) {
$publisher->send('HB'); // Distribute the heartbeat (all clients will subscribe)
sleep (5); // Heartbeat interval
$i++ // Clock that ticks up ~5 seconds at a time (alternatively,
// you could set a variable to store the timestamp of the last time the
// messages (A & B) were sent and then check to see if 5 minutes has elapsed).
if ($i >= 60) {
// 300 seconds--or perhaps a hair more--have elapsed, send the messages
$i = 0; // Rest the clock.
$publisher->send("A", ZMQ::MODE_SNDMORE);
$publisher->send("We don't want to see this");
$publisher->send("B", ZMQ::MODE_SNDMORE);
$publisher->send("We would like to see this");
} // Don't forget to close if statement.
}
<强> Client.php 强>
<?php
$context = new ZMQContext();
$subscriber = new ZMQSocket($context, ZMQ::SOCKET_SUB);
$SERVERIP = 'Where is the server?'; // Make sure this is correct and no firewall!
$subscriber->connect("tcp://$SERVERIP:5563");
$subscriber->setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, "B");
$subscriber->setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, 'HB'); // Subscribe to the heartbeat
$heartMonitor = time(); // Time we started listening.
while (true) {
$address = $subscriber->recv();
$more = $subscriber->getSockOpt(ZMQ::SOCKOPT_RCVMORE); // See if this is a multipart message
if ($more) {
// Message has second part--normally there would be a loop for variable length messages.
$contents = $subscriber->recv();
}
if ($address == 'HB') {
// Message is the heartbeat, would send this to additional
// application components and have them listen for heartbeat as well.
$heartMonitor = time(); // Time last heartbeat received in seconds
}else{
// Message is your content message; Do stuff.
printf ("[%s] %s%s", $address, $contents, PHP_EOL);
$heartMonitor = time(); // It doesn't matter which message was just received, both confirm connection.
}
$timeout = 20; // At least 3 heartbeat signals were missed.
if ($heartMonitor < (time() - $timeout)) {
// Connection lost. Alert user, fallback, or attempt reconnect, etc. here.
break;
}
} // Don't forget to close while loop.
最后,有一些ZeroMQ options用于修改TCP设置;但是,我不确定这支持得多好。此外,它不像心跳那样在应用程序级别提供可靠性检查。
因此,最好保持连接打开(不要错过消息,这实际上是与其他协议相比大量延迟减少的地方);你不想重新连接很多东西。此外,没有可靠的方法来更改服务器,网络设备和客户端上的TCP设置。最好的方法是确认应用程序级别的通信。
我希望这会有所帮助并让你朝着正确的方向前进。我没有测试过这段代码,但我会尝试明天(然后编辑这篇文章)。