НАБЛЮДЕНИЕ : Браузер зависает безо всяких ошибок.
Это вполне законное состояние. Чтобы это произошло, вполне достаточно «пропустить» поступление первого REQ
уже отправленного запроса и из-за удовольствия зависит от распределенного конечного состояния автомата,мы попадаем в незаменимый тупик, где сторона REQ
ждет ответа, который никогда не придет (см. далее), а сторона REP
ждет запроса, который никогда не поступит (см. REQ
сторона уже ждет) и такое состояние остается навсегда.
Лучший следующий шаг:
В случае, если никто никогда не работал с ZeroMQ,
илиникогда не встречал концепцию искусства Zen-of-Zero ,
, здесь можно с первого взгляда взглянуть на "ZeroMQ Принципы менее чем за пять секунд ", прежде чем углубляться в детали
Старт
с безоговорочно работающими архетипами - пара PUSH / PULL
симплекс-каналов, которые не требуют двухэтапного dFSA REQ-REP-REQ-REP-REQ-REP-...-{deadlock}
... принципиально неизбежного терминимальное состояние, в котором просто никогда не уверен , когда это произойдет, но это произойдет ... через некоторое время: o)
Далее,
может повысить надежность потока сообщений, используя zmq_setsockopt( ZMQ_IMMEDIATE, 1 )
, что позволяет избежать перемещения сообщений по неполным соединениям между / между узлами.
Всегда
предпочитают неблокирующие формы .recv()
-методов, лучше всего с предварительным тестированием присутствия сообщения с .poll()
-методом. Poller
-класс, хотя и доступен во многих языковых привязках, не всегда так удобен и гибок, как использование явного .poll()
-метода непосредственно в Socket
-экземпляре.
Также не стесняйтесь читать больше о тонкой настройке инструментов ZeroMQ и других значениях Искусства Zen-of-Zero здесь .
Макет на стороне сервера: As {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-эра и .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() ) )