Python中的ZMQ套接字优雅终止

Python中的ZMQ套接字优雅终止,python,sockets,signals,zeromq,Python,Sockets,Signals,Zeromq,我有下面的ZMQ脚本 #!/usr/bin/env python2.6 import signal import sys import zmq context = zmq.Context() socket = context.socket(zmq.SUB) def signal_term_handler(signal, fname): socket.close() sys.exit(0) def main(): signal.signal(signal.SIG

我有下面的ZMQ脚本

#!/usr/bin/env python2.6


import signal
import sys
import zmq


context = zmq.Context()
socket = context.socket(zmq.SUB)

def signal_term_handler(signal, fname):
    socket.close()
    sys.exit(0)

def main():
    signal.signal(signal.SIGTERM, signal_term_handler)

    socket.connect('tcp://16.160.163.27:8888')
    socket.setsockopt(zmq.SUBSCRIBE, '')
    print 'Waiting for a message'

    while True:
        (event, params) = socket.recv().split()
        # ... doing something with that data ...

if __name__ == '__main__':
    main()
当I
Ctrl-C
时,会出现以下错误:

Traceback (most recent call last):
  File "./nag.py", line 28, in <module>
    main()
  File "./nag.py", line 24, in main
    (event, params) = socket.recv().split()
  File "socket.pyx", line 628, in zmq.backend.cython.socket.Socket.recv (zmq/backend/cython/socket.c:5616)
  File "socket.pyx", line 662, in zmq.backend.cython.socket.Socket.recv (zmq/backend/cython/socket.c:5436)
  File "socket.pyx", line 139, in zmq.backend.cython.socket._recv_copy (zmq/backend/cython/socket.c:1771)
  File "checkrc.pxd", line 11, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:5863)
KeyboardInterrupt
回溯(最近一次呼叫最后一次):
文件“/nag.py”,第28行,在
main()
文件“/nag.py”,第24行,主
(事件,参数)=socket.recv().split()
zmq.backend.cython.socket.socket.recv(zmq/backend/cython/socket.c:5616)中的文件“socket.pyx”,第628行
zmq.backend.cython.socket.socket.recv(zmq/backend/cython/socket.c:5436)中的文件“socket.pyx”,第662行
文件“socket.pyx”,第139行,在zmq.backend.cython.socket中。\u recv_copy(zmq/backend/cython/socket.c:1771)
文件“checkrc.pxd”,第11行,在zmq.backend.cython.checkrc.\u check\u rc(zmq/backend/cython/socket.c:5863)中
键盘中断
现在,我想我已经处理好了套接字的关闭,当接收到来自用户的终止信号时,非常好,那么为什么我会收到这些丑陋的消息呢。我错过了什么

注意我在Google和StackOverflow上做了一些搜索,但没有找到任何解决此问题的方法

谢谢


EDIT向任何到此为止的人建议了一种非常好且健壮的方法来处理终止或执行过程中的任何异常。

使用SIGINT而不是应该修复它的SIGTERM

事件处理方法 虽然演示代码很小,但现实世界中的系统(多主机/多进程通信系统越多)通常应处理其主控制回路中的所有负面影响事件

try:
    context = zmq.Context()         # setup central Context instance
    socket  = ...                   # instantiate/configure all messaging archetypes
    # main control-loop ----------- # ----------------------------------------
    #
    # your app goes here, incl. all nested event-handling & failure-resilience
    # ----------------------------- # ----------------------------------------
except ...:
    #                               # handle IOErrors, context-raised exceptions
except Keyboard Interrupt:
    #                               # handle UI-SIG
except:
    #                               # handle other, exceptions "un-handled" above
finally:
    #                               # GRACEFULL TERMINATION
    # .setsockopt( zmq.LINGER, 0 )  #           to avoid hanging infinitely
    # .close()                      # .close()  for all sockets & devices
    #
    context.term()                  #           Terminate Context before exit
现场清洁 人们可能会想到下面的代码!但是不需要它用于插座关闭

插座会自动关闭

然而,这是手动操作的方式

此外,我列出了所有不同的有用信息,以了解销毁、关闭或清理主题的含义

试试看:
context=zmq.context()
socket=context.socket(zmq.ROUTER)
socket.bind(套接字路径)
# ....
最后:
context.destroy()#或表示优雅destroy的term()
键盘中断和修复时出错 在继续之前!错误原因:

Traceback (most recent call last):
  File "/usr/lib/python3.9/runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
...
    msg = self.recv(flags)
  File "zmq/backend/cython/socket.pyx", line 781, in zmq.backend.cython.socket.Socket.recv
  File "zmq/backend/cython/socket.pyx", line 817, in zmq.backend.cython.socket.Socket.recv
  File "zmq/backend/cython/socket.pyx", line 186, in zmq.backend.cython.socket._recv_copy
  File "zmq/backend/cython/checkrc.pxd", line 13, in zmq.backend.cython.checkrc._check_rc
KeyboardInterrupt
这只是键盘中断错误

只是抓住它!会解决问题的

例如:

试试看:
context=zmq.context()
socket=context.socket(zmq.ROUTER)
socket.bind(套接字路径)
# ...
除键盘中断外:
打印(“>用户强制退出!”)
宾果,错误不再显示

现在不需要终止上下文!它将自动完成

还要注意:如果您没有捕捉到键盘中断!只需做一个
最后:
块并单独运行
context.term()!这个过程将永远挂起

最后:
socket.close()#假设上下文中有一个套接字
上下文。术语()

最后:
context.destroy()
将抛出相同的错误!这证明了错误是键盘中断的上升!应该在图书馆里找到的!又扔了

只有捕捉键盘中断才行

键盘中断除外:
打印(“>用户强制退出!”)
最后:
context.destroy()#手动(不需要)
行!但是添加finally块完全没有用!并手动销毁(关闭插座+终止)

让我告诉你为什么

如果很匆忙,请转到python中的,无需在退出时进行清理部分全部结束

终止是如何工作的,为什么 从zguide:

它声明我们需要关闭所有邮件!还有所有的插座!只有在此之前,终止才会解除阻止并使代码退出

还有c郎!api将通过
zmq\u ctx\u destroy()
关闭套接字并销毁消息

有很多事情需要知道:

内存泄漏是一回事,但ZeroMQ对如何退出应用程序相当挑剔。原因是技术性的和痛苦的,但结果是如果您让任何套接字保持打开状态,zmq\u ctx\u destroy()函数将永远挂起。即使关闭所有套接字,zmq\u ctx\u destroy()默认情况下,如果存在挂起的连接或发送,则将永远等待,除非在关闭这些套接字之前将这些套接字上的延迟设置为零

我们需要担心的ZeroMQ对象是消息套接字上下文。幸运的是,它非常简单,至少在简单的程序中是如此:

  • 尽可能使用zmq_send()和zmq_recv(),因为这样可以避免使用zmq_msg_t对象
  • 如果确实使用了zmq_msg_recv(),请始终在处理完接收到的消息后立即释放该消息,方法是调用zmq_msg_close()
  • 如果要打开和关闭很多套接字,这可能是需要重新设计应用程序的信号。在某些情况下,套接字句柄在销毁上下文之前不会被释放
  • 退出程序时,关闭套接字,然后调用zmq_ctx_destroy()。这破坏了上下文
用于销毁上下文和终止的Python api 在pyzmq!
Context.term()
调用
zmq\u ctx\u destroy()

另一方面,方法
Context.destroy()
不仅是
zmq\u ctx\u destroy()
,而且还可以关闭上下文的所有套接字!然后调用
Context.term()
,调用
zmq\u ctx\u destroy()

来自python

销毁 注意destroy()不是
zmq\u ctx\u destroy()
term()

destroy()=上下文套接字close()+term()

关闭与此上下文关联的所有套接字,然后终止上下文

警告