Как получить ответ на запрашивающий сокет без блокировки? - PullRequest
1 голос
/ 07 ноября 2019

Я давно использую простой шаблон запрос / ответ (клиент / сервер), и он очень стабилен. Однако я попытался улучшить это, чтобы ни клиент, ни сервер не могли зависнуть, если что-то пошло не так с другим.

Исходный (блокирующий) шаблон выглядит следующим образом:

server.php

$zmq = new ZMQContext;
$sock = new ZMQSocket( $zmq, ZMQ::SOCKET_REP );
$sock->bind('tcp://*:5555');
while( true ){
    echo "Server waiting..\n";
    $ping = $sock->recv();
    echo "Acknowledging ",$ping,"..\n";
    $sock->send('Pong');
}

client.php

$zmq = new ZMQContext;
$sock = new ZMQSocket( $zmq, ZMQ::SOCKET_REQ );
$sock->connect('tcp://localhost:5555');

echo "Pinging..\n";
$sock->send('Ping');

echo "Client waiting..\n";
$pong = $sock->recv();
echo $pong," in reply. exiting.\n";

Это прекрасно работает, за исключением случаев, когда сервер умирает между получением запроса и отправкойВ ответ клиент зависнет навсегда.

Я хочу выполнить вызовы $sock->recv без блокировки и разрешить тайм-аут, если ответа нет. Я пытался добиться этого, хотя опрос. например, замена блокирующего вызова recv сверху чем-то вроде этого на стороне клиента:

client.php (опрос)

$zmq = new ZMQContext;
$sock = new ZMQSocket( $zmq, ZMQ::SOCKET_REQ );
$sock->connect('tcp://localhost:5555');

echo "Pinging..\n";
$sock->send('Ping');
echo "Client polling..\n";

$poller = new ZMQPoll;
$poller->add( $sock, ZMQ::POLL_IN );
$readable = [];
$writeable = [];
$poller->poll( $readable, $writeable, 1000 );
foreach( $readable as $sock ){
    $pong = $sock->recv();
    echo $pong," in reply. exiting.\n";
    exit(0);
}
echo "No reply after 1s\n";

Однако, я думаю, что этот подходвозникает риск того, что полученный ответ может быть предназначен для другого клиента, если два или более клиентов отправили запрос примерно в одно и то же время. Я предполагаю , что синхронный метод гарантирует, что этого не произойдет, но метод опроса нарушает это?

Итак, мой вопрос вкратце. Как запрашивающий сокет должен получить ответ без блокировки, при этом гарантируя, что сообщение не предназначено для другого клиента?

1 Ответ

0 голосов
/ 07 ноября 2019

Q : Как запрашивающий сокет должен получить ответ без блокировки, при гарантии сообщение не предназначено для другого клиента?

Добро пожаловать в Zen-of-Zero (включая нулевую гарантию)

Помимо стратегий, как обойти взаимные тупики, REQ/REP dFSA наверняка попадет (кто-то просто не знает, как скоро это произойдет, но это произойдет), где я всегда предпочитаю двустороннее неблокирующее .poll() -пред- .recv() циклическое сканирование, гарантировано - " доставка " - и - " маршрутизация " - проблема на другом уровне.

REQ/REP (задокументировано в ZMTP / RFC (28)) сам по себе работает следующим образом:

Каждый отправленный запрос циклически разбирается среди всех служб, и каждый полученный ответ сопоставляется с последним выданным запросом.

Если сервисы недоступны, любая операция отправки в сокете блокируется до тех пор, пока не станет доступен хотя бы один сервис. Сокет REQ не должен сбрасывать сообщения.

, наблюдаемый на стороне REQ.send(), и

Каждый полученный запрос является справедливой очередьюиз всех клиентов, и каждый отправленный ответ направляется клиенту, который отправил последний запрос. Если первоначальный запросчик больше не существует, ответ молча отбрасывается.

наблюдается на стороне REP.recv().

Последнее предложение решило незаконно присвоенную доставкудля случаев, когда сторона REQ перестала существовать непосредственно перед вызовом REP.send().

Сообщения, с другой стороны,
могут содержать самопроверку соответствующей доставки (можно проверить 'Например, перед принятием решения {process | забудьте})
может содержать криптографически гарантированную форму «спасения вашей шеи» для случаев, когда полезные данные попадают не в те руки (с нулевым значением, если у них нет также «правильного»). «-Ключ) - так можно отправлять всем без греха нарушения любую политику защиты контента (но все же довольно жестокая и« дорогая »стратегия с точки зрения ресурсов, не так ли?)
все,
на самом деле все,
зависит от ваших предпочтений
и уровней надежности, приемлемых с учетом уровня паранойи, связанной с безопасностью (и главным образом из-за разумных уровней), которая была установлена ​​и взаимнопризнан правдоподобным среди всех участников и владельцев рисков, связанных с проблемой домена.


Лучший следующий шаг:

Просмотрите все требования и риски проблемной области, оцените разумную стоимость проблемысмягчения и принять решение о разумной, но рентабельной разработке специализированного пользовательского распределенного протокола уровня приложений, который добавит все требования, которые ZeroMQ сознательно пропустил для включения в интеллектуальные, масштабируемые, почти нулевые латентные архетипы (который может не подходить для использования «как есть», так как любое из ваших требований к высокоуровневым дополнениям вводит больше работы, которая должна быть выполнена до / во время / после того, как сообщение должно было быть доставлено)

...