![](/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.