如果脚本从 CLI/shell 而不是从 APACHE/web 请求启动,ZeroMQ send/receive on PHP 工作
ZeroMQ send/receive on PHP works if script launched from CLI/shell but not from APACHE/web request
我正在为 PHP 测试 ZeroMQ。我的目标是将消息发送到 Python 脚本。
如果我从 PHP cli
启动传输脚本,一切正常
php /path/to/myscript.php
如果是网络请求则失败。我试过从 PHP cli 执行服务器脚本,如上(这似乎是更合乎逻辑的方式)和网络请求。
我有一个 Centos 7 服务器,通过 PECL 安装 PHP 7.2 和 ZeroMQ 1.1.3。
我什至尝试在客户端脚本中使用 shell_exec/exec 启动上述命令,但它不起作用。连接工作正常,但它既不发送也不接收。
客户代码:
$context = new ZMQContext();
// Socket to talk to server
echo "Connecting to hello world server...\n";
$requester = new ZMQSocket($context, ZMQ::SOCKET_REQ);
$currentObject = $requester->connect("tcp://localhost:5555");
for ($request_nbr = 0; $request_nbr != 10; $request_nbr++) {
printf ("Sending request %d...\n", $request_nbr);
$risSend = $requester->send("Hello", ZMQ::MODE_NOBLOCK);
print_r($risSend);
$reply = $requester->recv();
printf ("Received reply %d: [%s]\n", $request_nbr, $reply);
}
服务器代码:
$context = new ZMQContext(1);
// Socket to talk to clients
$responder = new ZMQSocket($context, ZMQ::SOCKET_REP);
$responder->bind("tcp://*:5555");
while (true) {
// Wait for next request from client
$request = $responder->recv();
printf ("Received request: [%s]\n", $request);
// Send reply back to client
$responder->send("World");
}
浏览器卡住,没有任何错误。即使使用超时,它也会达到限制并退出,但我无法收到任何错误消息。
OBSERVATION : The browser gets stuck, without any error.
这是相当合法的状态。要做到这一点,"miss" 第一个 REQ
端已经发送的请求的到来就足够了,并且由于高兴,确实取决于分布式有限状态自动机,我们陷入了一个无法挽救的死锁,REQ
端等待一个永远不会到达的答案(见下一个),REP
端等待一个永远不会到达的请求(参见 REQ
端已经在等待)并且这种状态永远存在。
最好的下一步:
如果你从未使用过 ZeroMQ,
或者从未接触过零之禅、
的概念
人们可能喜欢先看看 ,然后再深入了解更多细节
开始
具有无条件工作原型 - 一对 PUSH / PULL
单纯形通道,不需要 dFSA 两步 REQ-REP-REQ-REP-REQ-REP-...-{deadlock}
.. . 基本上是不可避免的最终状态,人们永远无法确定何时它会发生,但它会......在以后的某个时间:o)
接下来,
可以增加消息流的稳健性,使用 zmq_setsockopt( ZMQ_IMMEDIATE, 1 )
避免将消息移动到对等点之间的不完整连接上。
总是
更喜欢 .recv()
-methods 的非阻塞形式,最好使用 .poll()
-method 预先测试消息存在。 Poller
-class,虽然在许多语言绑定中可用,但并不总是像直接在Socket
-实例。
也可以随意阅读更多关于微调 ZeroMQ 工具 和零禅艺术的其他含义here。
服务器端模型: 作为 { PASS | FAIL }-证明 .send()---.recv()
-交付链有效?
<?php /* Create new PUSH-ing end */
$aCTX = new ZMQContext();
try { /* Try: things may turn wreck havoc */
$PUSHer = $aCTX->getSocket(, ZMQ::SOCKET_PUSH );
echo "POSACK'd: .getSocket() was made\n";
}
catch ( ZMQSocketException $e ){
echo " NACK'd: I told you ...\n"; /* Handle with care ... */
if ( $e->getCode() === ZMQ::ERR_... ) {
echo " - Got ERR_..., read ZeroMQ API documentation for details\n";
} else {
die( " - Get ERR: " . $e->getMessage() );
}
}
try { /* Try: things may turn wreck havoc */
$PUSHer->bind( "tcp://A.B.C.D:NNN" ); /* IP address to .connect() */
echo "POSACK'd: .bind() was made\n";
}
catch ( ZMQSocketException $e ){
echo " NACK'd: I told you ...\n"; /* Handle with care ... */
if ( $e->getCode() === ZMQ::ERR_... ) {
echo " - Got ERR_..., read ZeroMQ API documentation for details\n";
} else {
die( " - Get ERR: " . $e->getMessage() );
}
}
$retries = 1234567;
do { /* Start a loop */
try { /* Try: to PUSH.send() */
echo "Trying to send a message #" . ( 1234568 - $retries ) . "\n";
$PUSHer->send( "This is a message", ZMQ::MODE_DONTWAIT );
echo "POSACK'd: PUSHer.send() was made\n";
}
} catch ( ZMQSocketException $e ) {
echo " NACK'd: I told you ...\n"; /* Handle with care ... */
if ( $e->getCode() === ZMQ::ERR_... ) {
echo " - Got ERR_..., read ZeroMQ API documentation for details\n";
} else { /* For all ERR_... states */
die( " - Got ERR_...: " . $e->getMessage() );
}
}
/* --------------------------------------------------------------------
Here one may add an attempt to .recv( $PULLer, ZMQ::MODE_DONTWAIT );
and test for a non-empty string returned
-------------------------------------------------------------------- */
usleep( 1 ); /* Sleep a bit between operations */
} while ( --$retries );
?>
客户端模型,用于测试 PUSH-er 和 .send()
-s
import time, datetime, zmq; print( "Thissssss Sssssssssssssssssssssssssssssssssssssssnake uses ZeroMQ ver:{0:}".format( zmq.__version__ ) )
aCtx = zmq.Context()
aPull= aCtx.Socket( zmq.PULL )
aPull.setsockopt( zmq.LINGER, 0 ) # always ... be explicit
aPull_address2c = "tcp://A.B.C.D:NNN"
M0 = "{0:} try a .connect( {1:} ), if it gets to PUSH-er side"
M1 = "{0:} try a .recv(), if it gets any message"
M2 = "{0:} got a .recv()->[[[ {1:} ]]]"
M3 = "{0:} EXC'd will gracefully release resources and terminate..."
M4 = "{0:} did"
try:
print( M0.format( datetime.datetime.isoformat( datetime.datetime.now() ),
aPull_address2c
)
)
aPull.connect( aPull_address2c );
while True:
print( M1.format( datetime.datetime.isoformat( datetime.datetime.now() ) )
m = aPull.recv( zmq.NOBLOCK ) # always ... avoid blocking waits
if ( len( m ) > 0 ):
print( M2.format( datetime.datetime.isoformat( datetime.datetime.now() ),
str( m ) # always ... fused to str()
)
)
time.sleep( 5 )
else:
time.sleep( 1 )
pass
################################################################
# Here one may add an attempt to aPush.send( M4, zmq.NOBLOCK )
# and test if the reverse path aPush->$PULLer goes well
################################################################
except:
print( M3.format( datetime.datetime.isoformat( datetime.datetime.now() ) )
finally:
aPull.close() # always ... be explicit
aCtx.term() # always ... be explicit
print( M4.format( datetime.datetime.isoformat( datetime.datetime.now() ) )
好的,我终于找到了解决方案。
感谢@user3666197,我设法得到了一个错误。这是一个 "permission denied" 错误。
对于 CentOS(可能还有所有 linux SELinux 系统),您必须为 ZMQ 使用的端口添加规则 用于网络服务器。
示例:
semanage port -a -t http_port_t -p tcp 5555
我正在为 PHP 测试 ZeroMQ。我的目标是将消息发送到 Python 脚本。 如果我从 PHP cli
启动传输脚本,一切正常php /path/to/myscript.php
如果是网络请求则失败。我试过从 PHP cli 执行服务器脚本,如上(这似乎是更合乎逻辑的方式)和网络请求。
我有一个 Centos 7 服务器,通过 PECL 安装 PHP 7.2 和 ZeroMQ 1.1.3。
我什至尝试在客户端脚本中使用 shell_exec/exec 启动上述命令,但它不起作用。连接工作正常,但它既不发送也不接收。
客户代码:
$context = new ZMQContext();
// Socket to talk to server
echo "Connecting to hello world server...\n";
$requester = new ZMQSocket($context, ZMQ::SOCKET_REQ);
$currentObject = $requester->connect("tcp://localhost:5555");
for ($request_nbr = 0; $request_nbr != 10; $request_nbr++) {
printf ("Sending request %d...\n", $request_nbr);
$risSend = $requester->send("Hello", ZMQ::MODE_NOBLOCK);
print_r($risSend);
$reply = $requester->recv();
printf ("Received reply %d: [%s]\n", $request_nbr, $reply);
}
服务器代码:
$context = new ZMQContext(1);
// Socket to talk to clients
$responder = new ZMQSocket($context, ZMQ::SOCKET_REP);
$responder->bind("tcp://*:5555");
while (true) {
// Wait for next request from client
$request = $responder->recv();
printf ("Received request: [%s]\n", $request);
// Send reply back to client
$responder->send("World");
}
浏览器卡住,没有任何错误。即使使用超时,它也会达到限制并退出,但我无法收到任何错误消息。
OBSERVATION : The browser gets stuck, without any error.
这是相当合法的状态。要做到这一点,"miss" 第一个 REQ
端已经发送的请求的到来就足够了,并且由于高兴,确实取决于分布式有限状态自动机,我们陷入了一个无法挽救的死锁,REQ
端等待一个永远不会到达的答案(见下一个),REP
端等待一个永远不会到达的请求(参见 REQ
端已经在等待)并且这种状态永远存在。
最好的下一步:
如果你从未使用过 ZeroMQ,
或者从未接触过零之禅、
的概念
人们可能喜欢先看看
开始
具有无条件工作原型 - 一对 PUSH / PULL
单纯形通道,不需要 dFSA 两步 REQ-REP-REQ-REP-REQ-REP-...-{deadlock}
.. . 基本上是不可避免的最终状态,人们永远无法确定何时它会发生,但它会......在以后的某个时间:o)
接下来,
可以增加消息流的稳健性,使用 zmq_setsockopt( ZMQ_IMMEDIATE, 1 )
避免将消息移动到对等点之间的不完整连接上。
总是
更喜欢 .recv()
-methods 的非阻塞形式,最好使用 .poll()
-method 预先测试消息存在。 Poller
-class,虽然在许多语言绑定中可用,但并不总是像直接在Socket
-实例。
也可以随意阅读更多关于微调 ZeroMQ 工具 和零禅艺术的其他含义here。
服务器端模型: 作为 { PASS | FAIL }-证明 .send()---.recv()
-交付链有效?
<?php /* Create new PUSH-ing end */
$aCTX = new ZMQContext();
try { /* Try: things may turn wreck havoc */
$PUSHer = $aCTX->getSocket(, ZMQ::SOCKET_PUSH );
echo "POSACK'd: .getSocket() was made\n";
}
catch ( ZMQSocketException $e ){
echo " NACK'd: I told you ...\n"; /* Handle with care ... */
if ( $e->getCode() === ZMQ::ERR_... ) {
echo " - Got ERR_..., read ZeroMQ API documentation for details\n";
} else {
die( " - Get ERR: " . $e->getMessage() );
}
}
try { /* Try: things may turn wreck havoc */
$PUSHer->bind( "tcp://A.B.C.D:NNN" ); /* IP address to .connect() */
echo "POSACK'd: .bind() was made\n";
}
catch ( ZMQSocketException $e ){
echo " NACK'd: I told you ...\n"; /* Handle with care ... */
if ( $e->getCode() === ZMQ::ERR_... ) {
echo " - Got ERR_..., read ZeroMQ API documentation for details\n";
} else {
die( " - Get ERR: " . $e->getMessage() );
}
}
$retries = 1234567;
do { /* Start a loop */
try { /* Try: to PUSH.send() */
echo "Trying to send a message #" . ( 1234568 - $retries ) . "\n";
$PUSHer->send( "This is a message", ZMQ::MODE_DONTWAIT );
echo "POSACK'd: PUSHer.send() was made\n";
}
} catch ( ZMQSocketException $e ) {
echo " NACK'd: I told you ...\n"; /* Handle with care ... */
if ( $e->getCode() === ZMQ::ERR_... ) {
echo " - Got ERR_..., read ZeroMQ API documentation for details\n";
} else { /* For all ERR_... states */
die( " - Got ERR_...: " . $e->getMessage() );
}
}
/* --------------------------------------------------------------------
Here one may add an attempt to .recv( $PULLer, ZMQ::MODE_DONTWAIT );
and test for a non-empty string returned
-------------------------------------------------------------------- */
usleep( 1 ); /* Sleep a bit between operations */
} while ( --$retries );
?>
客户端模型,用于测试 PUSH-er 和 .send()
-s
import time, datetime, zmq; print( "Thissssss Sssssssssssssssssssssssssssssssssssssssnake uses ZeroMQ ver:{0:}".format( zmq.__version__ ) )
aCtx = zmq.Context()
aPull= aCtx.Socket( zmq.PULL )
aPull.setsockopt( zmq.LINGER, 0 ) # always ... be explicit
aPull_address2c = "tcp://A.B.C.D:NNN"
M0 = "{0:} try a .connect( {1:} ), if it gets to PUSH-er side"
M1 = "{0:} try a .recv(), if it gets any message"
M2 = "{0:} got a .recv()->[[[ {1:} ]]]"
M3 = "{0:} EXC'd will gracefully release resources and terminate..."
M4 = "{0:} did"
try:
print( M0.format( datetime.datetime.isoformat( datetime.datetime.now() ),
aPull_address2c
)
)
aPull.connect( aPull_address2c );
while True:
print( M1.format( datetime.datetime.isoformat( datetime.datetime.now() ) )
m = aPull.recv( zmq.NOBLOCK ) # always ... avoid blocking waits
if ( len( m ) > 0 ):
print( M2.format( datetime.datetime.isoformat( datetime.datetime.now() ),
str( m ) # always ... fused to str()
)
)
time.sleep( 5 )
else:
time.sleep( 1 )
pass
################################################################
# Here one may add an attempt to aPush.send( M4, zmq.NOBLOCK )
# and test if the reverse path aPush->$PULLer goes well
################################################################
except:
print( M3.format( datetime.datetime.isoformat( datetime.datetime.now() ) )
finally:
aPull.close() # always ... be explicit
aCtx.term() # always ... be explicit
print( M4.format( datetime.datetime.isoformat( datetime.datetime.now() ) )
好的,我终于找到了解决方案。 感谢@user3666197,我设法得到了一个错误。这是一个 "permission denied" 错误。
对于 CentOS(可能还有所有 linux SELinux 系统),您必须为 ZMQ 使用的端口添加规则 用于网络服务器。
示例:
semanage port -a -t http_port_t -p tcp 5555