![](/img/trans.png)
[英]How to can I serialize data to Communication between C++ zmq client and Python zmq Server
[英]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
套接字应删除消息的第一部分,并使用它来确定消息应路由到的对等方的身份,并且不可路由的消息将导致EHOSTUNREACH
或EAGAIN
错误。
要打开与服务器的连接,请使用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.