繁体   English   中英

如何将Python ZMQ链接到标准UDP或TCP服务器(旧版,大约15年前使用C ++编写)

[英]How to link Python ZMQ to a standard UDP or TCP server (legacy, written using C++ ~ 15 years ago)

我需要在用Python编写的软件包(PsychoPy,用于心理/行为实验)与可以使用UDP或TCP的旧版C ++软件之间进行通信。 特别是在Python / PsychoPy方面,我需要一个类似Matlab的pnet()的异步进程,该进程将轮询套接字以查看是否有任何要读取的数据,如果是,则处理数据,否则,继续进行下去。

向我推荐了ZMQ; 但是我使用zmq_polling看到的所有示例代码都假定发送和接收都是通过ZMQ协议进行的。 是否有一些简单的Python ZMQ代码连接到非zmq TCP或UDP源,并且在没有数据可读取的情况下进行轮询以检查数据是否存在而不会挂断?

谢谢阿尼鲁达(Aniruddha)

import zmq
import time


# Prepare our context and sockets
context = zmq.Context()

# Bind socket to local host
receiver = context.socket(zmq.PULL)
receiver.bind("tcp://129.236.162.112:55513")
#print( "Connected to server with port %s" % port_push)

# Initialize poll set
poller = zmq.Poller()
poller.register(receiver, zmq.POLLIN)



# Process messages from socket
while True:
    print('Entered the queue')
    try:
        socks = dict(poller.poll())
    except KeyboardInterrupt:
        break

    if receiver in socks:
        message = receiver.recv()
        # process task
        print(repr(message))


    else:
        print('Nothing to show')

    time.sleep(0.01)

我可以从旧版C ++机器发送小的TCP数据包; 它们被发送出去而没有任何错误消息,这意味着没有问题。 但是此Python代码没有任何反应

上面的代码进入“ try”,并停留在那里。

如何访问错误/状态消息进行调试?

谢谢阿尼鲁达(Aniruddha)

欢迎来到零之禅:是的,这是可能的

您的帖子同时提出了许多问题。 让我们从一个到另一个。


问题1如何访问错误/状态消息进行调试?

ZeroMQ文档提供了用于此目的的工具。 C端绑定共有一个显式的返回码,可以通过assert()进行检查,还可以从errno检索更多详细信息:

void *ctx    = zmq_ctx_new();                     assert( ctx     && "EXC: Context failed to instantiate" );
void *socket = zmq_socket( ctx, ZMQ_STREAM );     assert( socket  && "EXC: Socket failed to instantiate" );
int   rc     = zmq_bind( socket, "tcp://*:8080" );assert( rc == 0 && "EXC: Bind failed to setup a Transport-Class" );

Q2 + 3是否有一些简单的Python ZMQ代码连接到非zmq TCP或UDP源(2) ,并进行轮询(3)以检查是否存在数据,如果没有要读取的数据就不会挂断?

为此(2) ,ZeroMQ框架在3.2+左右的某个版本中配备了STREAM可扩展正式通信模式原型。 如果不确定,那么ZeroMQ架构如何使用Context,Context的Socket原型,Socket的传输类AccessPoint,您可能想 深入了解更多细节之前,先简短阅读不到5秒的 ZeroMQ 原理 ”。 关于ZeroMQ

使用tcp://传输时,类型为ZMQ_STREAM的套接字用于从非ØMQ对等方发送和接收TCP数据。 ZMQ_STREAM套接字可以充当客户端和/或服务器,以异步方式发送和/或接收TCP数据。

当接收TCP数据时,在将消息传递给应用程序之前, ZMQ_STREAM套接字应在消息部分之前包含消息的原始对等方的身份。 接收到的消息从所有连接的同级之间公平排队。

发送TCP数据时, ZMQ_STREAM套接字应删除消息的第一部分,并使用它来确定消息应路由到的对等方的身份,并且不可路由的消息将导致EHOSTUNREACHEAGAIN错误。

要打开与服务器的连接,请使用zmq_connect调用,然后使用ZMQ_IDENTITY zmq_getsockopt调用获取套接字标识。

要关闭特定连接,请发送标识帧,然后发送零长度消息(请参见示例部分)。

建立连接后,应用程序将收到零长度的消息。 同样,当对等方断开连接(或连接断开)时,应用程序将接收零长度的消息。

您必须先发送一个标识帧,然后发送一个数据帧。 ZMQ_SNDMORE标志对于标识帧是必需的,但在数据帧上将被忽略。

轮询(3)的使用有两个前提:切勿使用任何.recv()方法的阻塞模式。 ZeroMQ具有标志来告诉该方法不要阻塞:python端的zmq.NOBLOCK 另外,围绕.poll()的非阻塞形式设计python代码,或使用.Poller()

例:

import zmq;                           print( zmq.zmq_version() ) # self-identify
aContext = zmq.Context();             print( "Context()", " instantiated." if zmq.zmq_errno() == 0 else " failed [#{}]".format( zmq.strerror( zmq.zmq_errno() ) ) )

aXmitSOCKET = aContext.socket( zmq.PUSH   ); aXmitSOCKET.setsockopt( zmq.LINGER, 0 ); ...
aCtrlSOCKET = aContext.socket( zmq.STREAM ); aCtrlSOCKET.setsockopt( zmq.LINGER, 0 ); ...

while True:
      if ( 0 == aXmitSOCKET.poll(  200, zmq.POLLIN ) ): # ~ 200 msec WAIT
         # ---------------------------------------------[aXmitPORT].hasNoIncomingMSG
         aCountDownREG -= 1                             #.DEC CDOWN as XmitPORT has no incoming DataToPREDICT_MSG
         aCountUpREG   += 1                             #.INC CNTUP
         if ( 0 == aCtrlSOCKET.poll( 1, zmq.POLLIN ) ): # ~   1 msec WAIT
            # ---------------------------------------------[aCtrlPORT].hasNoIncomingMSG
            ...
         else:                                          #
            # ---------------------------------------------[aCtrlPORT].hasAnIncomingMSG
            idF,aCMD = aCtrlSOCKET.recv_multipar( zmq.NOBLOCK )  # .recv()<-MSG as CtrlPORT has an incoming COMMAND_MSG
            ...
#--------------
# finally:
_ = [ aCtrlSOCKET.send_multipart( [ anIdentityFRAME, "" ], zmq.NOBLOCK ) for anIdentityFRAME in aListOfIdFRAMEs ]
aCtrlSOCKET.close()
aXmitSOCKET.close()
#--------------
# always:
aContext.term()

还可以随时检查这些方法的实时文档:

>>> print( aCtrlSOCKET.recv_multipart.__doc__ )
Receive a multipart message as a list of bytes or Frame objects

        Parameters
        ----------
        flags : int, optional
            Any valid flags for :func:`Socket.recv`.
        copy : bool, optional
            Should the message frame(s) be received in a copying or non-copying manner?
            If False a Frame object is returned for each part, if True a copy of
            the bytes is made for each frame.
        track : bool, optional
            Should the message frame(s) be tracked for notification that ZMQ has
            finished with it? (ignored if copy=True)

        Returns
        -------
        msg_parts : list
            A list of frames in the multipart message; either Frames or bytes,
            depending on `copy`.

        Raises
        ------
        ZMQError
            for any of the reasons :func:`~Socket.recv` might fail

>>> print( aCtrlSOCKET.send_multipart.__doc__ )
Send a sequence of buffers as a multipart message.

        The zmq.SNDMORE flag is added to all msg parts before the last.

        Parameters
        ----------
        msg_parts : iterable
            A sequence of objects to send as a multipart message. Each element
            can be any sendable object (Frame, bytes, buffer-providers)
        flags : int, optional
            Any valid flags for :func:`Socket.send`.
            SNDMORE is added automatically for frames before the last.
        copy : bool, optional
            Should the frame(s) be sent in a copying or non-copying manner.
            If copy=False, frames smaller than self.copy_threshold bytes
            will be copied anyway.
        track : bool, optional
            Should the frame(s) be tracked for notification that ZMQ has
            finished with it (ignored if copy=True).

        Returns
        -------
        None : if copy or not track
        MessageTracker : if track and not copy
            a MessageTracker object, whose `pending` property will
            be True until the last send is completed.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM