zeromq: сброс состояния сокета REQ/REP
когда вы используете простой шаблон ZeroMQ REQ / REP, вы зависите от фиксированной последовательности send()->recv() / recv()->send (). As этой статья описывает, что вы попадаете в беду, когда участник отключается в середине запроса, потому что тогда вы не можете просто начать с получения следующего запроса от другого соединения, но государственная машина заставит вас отправить запрос на отключенный.
появился более элегантный способ решить эту проблему, так как упомянутая статья была написана?
повторно подключается единственный способ решить эту проблему (кроме не использования REQ/REP, но использовать другой шаблон)
4 ответов
хорошей новостью является то, что, начиная с ZMQ 3.0 и позже (современная эра), вы можете установить тайм-аут на сокете. Как отмечали другие в другом месте, вы должны сделать это после создания сокета, но перед его подключением:
zmq_req_socket.setsockopt( zmq.RCVTIMEO, 500 ) # milliseconds
затем, когда вы фактически пытаетесь получить ответ (после того, как вы отправили сообщение в сокет REP), вы можете поймать ошибку, которая будет утверждена, если тайм-аут превышен:
try:
send( message, 0 )
send_failed = False
except zmq.Again:
logging.warning( "Image send failed." )
send_failed = True
однако! Когда это произойдет, как наблюдаемый в другом месте, ваш сокет будет в забавном состоянии, потому что он все равно будет ожидать ответа. На данный момент я не могу найти ничего, что работает надежно, кроме перезапуска сокета. Обратите внимание, что если вы отключите() сокет, а затем повторно подключите() его, он все равно будет в этом плохом состоянии. Таким образом, вам нужно
def reset_my_socket:
zmq_req_socket.close()
zmq_req_socket = zmq_context.socket( zmq.REQ )
zmq_req_socket.setsockopt( zmq.RCVTIMEO, 500 ) # milliseconds
zmq_req_socket.connect( zmq_endpoint )
вы также заметите, что, поскольку я закрываю () D сокет, параметр тайм-аута приема был "потерян", поэтому важно установить, что на новом разъем.
надеюсь, это поможет. И я надеюсь, что это не окажется самым лучшим ответом на этот вопрос. :)
поскольку принятый ответ кажется мне ужасно грустным, я провел некоторое исследование и обнаружил, что все, что нам нужно, было на самом деле в документации.
на .setsockopt()
С правильным параметром может помочь вам сбросить состояние сокета-машина без жестоко уничтожить его и перестроить другой поверх предыдущего мертвого тела.
(да, мне нравится образ).
ZMQ_REQ_CORRELATE:
матч с ответами запросы
Поведение по умолчаниюREQ
сокеты должны полагаться на порядок сообщений для соответствия запросам и ответам, и этого обычно достаточно. Если этот параметр имеет значение1
наREQ
сокет будет префиксом исходящих сообщений с дополнительным фреймом, содержащим запросid
. Это означает, что полное сообщение (requestid
,identity
,0
,user frames…
). TheREQ
сокет отбросит все входящие сообщения, которые не начинаются с этих двух кадры.
Тип значения параметраint
Значение параметра unit0
,1
Значение по умолчанию0
Применимые типы сокетовZMQ_REQ
ZMQ_REQ_RELAXED:
ослабьте строгое чередование между запросом и ответом
По умолчаниюREQ
сокет не позволяет инициировать новый запрос с помощьюzmq_send(3)
пока не будет получен ответ на предыдущий. Когда установлено значение1
отправка другое сообщение разрешено и имеет эффект отключения базового соединения с одноранговым узлом, от которого ожидался ответ, вызывая попытку повторного подключения на транспортах, которые его поддерживают. Машина состояния запрос-ответ сбрасывается и новый запрос отправляется следующему доступному одноранговому узлу.
Если установлено значение1
, а также включитьZMQ_REQ_CORRELATE
для обеспечения правильного соответствия запросов и ответов. В противном случае поздний ответ на прерванный запрос может быть сообщен как ответ на заменяющее запросу.
Тип значения параметраint
Значение параметра unit0
,1
Значение по умолчанию0
Применимые типы сокетовZMQ_REQ
есть одно решение для этого, и это добавление таймаутов ко всем вызовам. Поскольку ZeroMQ сам по себе не обеспечивает простую функциональность таймаута, я рекомендую использовать подкласс сокета ZeroMQ, который добавляет параметр таймаута ко всем важным вызовам.
Итак, вместо вызова s.recv () вы бы назвали s.recv (timeout=5.0), и если ответ не вернется в течение этого 5-секундного окна, он не вернет None и прекратит блокировку. Я сделал тщетную попытку, когда бежал. в эту проблему.
Я на самом деле изучаю это на данный момент, потому что я ретро-подгонка устаревшей системы.
Я постоянно сталкиваюсь с кодом, который "должен" знать о состоянии соединения. Однако дело в том, что я хочу перейти к парадигме передачи сообщений, которую продвигает библиотека.
Я нашел следующую функцию : zmq_socket_monitor
что он делает, это контролировать сокет, переданный ему, и генерировать события, которые затем передаются конечная точка" inproc " - в этот момент Вы можете добавить код обработки, чтобы действительно что-то сделать.
здесь также есть пример (фактически тестовый код):github
У меня нет конкретного кода, чтобы дать на данный момент (возможно, в конце недели), но мое намерение состоит в том, чтобы ответить на подключение и разъединения, чтобы я мог фактически выполнить любой сброс логики требуется.
надеюсь, это поможет, и, несмотря на цитирование 4.2 docs, я использую 4.0.4 который, кажется, имеет функциональность также.
Примечание я заметил, что вы говорите о python выше, но вопрос помечен C++, поэтому мой ответ исходит от...