簡體   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