ZMQ DEALER - ROUTER Communication

后端 未结 2 1161
萌比男神i
萌比男神i 2020-12-09 23:39

I am currently working on a project that requires some communication over the network of a different data types from some entities of a distributed system and I am using ZMQ

2条回答
  •  死守一世寂寞
    2020-12-10 00:21

    The ( prematurely ) awarded answer does not meet defined properties.

    Distributed systems need to operate both smart and efficiently, as the agents are distributed and both error-analyses and deployed production-issues are extremely expensive to analyse / test / debug.

    Thus a copy/paste re-use of a problem-incompatible idea is not a way to achieve either the former, the less the latter.


    So, let's review the efficiency first:

    client-[A].send()-s a message, that O/P wanted to become server-side-[S].recv()-ed and re-broadcast to all other clients-[B,C,...], except the [A]-itself.

    The most resources-efficient approach to this is to properly configure the infrastructure tools for doing exactly this, without re-inventing wheel and/or using a fragile and performance-devastating scaffolding code(s).

    So:

    on the client-[*] side best use the below sketched primitive agent-concept. More complex setups, like using as clever event-handling facilities as Tkinter has evolved to have packed into the .mainloop() soft-real-time system, are better, yet it is not as easy to start design-battles on more than one front, so let's rather keep things simpler at this moment:

    zmq_VERSION      = zmq.zmq_version_info()
    anAgentsIDENTITY = whateverHashOrHumanReadableSTRING
    notMINE          = anAgentsIDENTITY
    
    if     zmq_VERSION[0] < 4:
               print "ZMQ{0:} ver < than expected, will exit".format( zmq_VERSION )
    aCTX = zmq.Context( 2 )                        # if performance boosting is needed
    
    #SUB ---------------------------------------------------------------------------
    aSUB = aCTX.socket( zmq.SUB )
    aSUB.setsockopt(    zmq.LINGER,          0 )   # protect your agent
    aSUB.setsockopt(    zmq.MAXMSGSIZE,      m )   # protect your agent from DoS
    aSUB.setsockopt(    zmq.AFFINITY,        1 )   # protect your server resources
    aSUB.setsockopt(    zmq.HEARTBEAT_IVL,   ivl ) #     set server helping Heartbeats
    aSUB.setsockopt(    zmq.HEARTBEAT_TTL,   ttl ) #     set server helping Heartbeats
    aSUB.setsockopt(    zmq.INVERT_MATCHING, 1 )   #   avoid server sending data back
    aSUB.setsockopt(    zmq.SUBSCRIBE,       notMINE )  #  NEVER .recv()-s  data back
    ...
    #SUB PERFORMANCE & RESOURCES TWEAKING DETAILS GO WAY BEYOND THE SCOPE OF THIS POST
    
    aSUB.connect(      "tcp://localhost:5557" )
    
    #PUSH --------------------------------------------------------------------------
    aPUSH = aCTX.socket( zmq.PUSH )
    ...
    #PUSH PERFORMANCE & RESOURCES TWEAKING DETAILS GO WAY BEYOND THE SCOPE OF THIS POST
    
    #main loop ---------------------------------------------------------------------
    pass; notSoftFLAG = True; anAgentSignsWithIdentityPREFIX = anAgentsIDENTITY
    while notSoftFLAG:
    
        if aReasonToSendSomethingToServer:
           aPUSH.send( anAgentSignsWithIdentityPREFIX
                     + ":::"
                     + aMsgPAYLOAD,
                       zmq.DONTWAIT
                       )                          # inspect ZMQError
           ...
           pass
    
        if aSUB.poll( 100 ):
           message = aSUB.recv( zmq.DONTWAIT )    #  NEVER .recv()-s own data back
           ...
           pass
    
    
        if aReasonToFlagLoopEXIT:
           notSoftFLAG = False
           ...
           pass
    
        if ...:
           ...
           pass
    
    #main loop ---------------------------------------------------------------------
    pass
    
    #########
    # ALWAYS:
    #          better using context-aware try:/except:/finally:
    
    aRetCODE = [ aSOCK.close() for aSOCK in ( aSUB, aPUSH, ) ]
    ...
    
    aCTX.term()
    #   .term()
    #########
    

    Server can avoid ALL hassles with any need for any ad-hoc handling:

    all being well tuned inside the ZeroMQ infrastructure:

    pass;  zmq_VERSION = zmq.zmq_version_info()
    if     zmq_VERSION[0] < 4:
               print "ZMQ{0:} ver < than expected, will exit".format( zmq_VERSION )
    
    aCTX = zmq.Context( 2 )                        # if performance boosting is needed
    
    #PUB ---------------------------------------------------------------------------
    aPUB = aCTX.socket( zmq.PUB )
    aPUB.setsockopt(    zmq.LINGER,          0 )   # protect your server
    aPUB.setsockopt(    zmq.MAXMSGSIZE,      m )   # protect your server from DoS
    aPUB.setsockopt(    zmq.AFFINITY,        3 )   # protect your server resources
    aPUB.setsockopt(    zmq.HEARTBEAT_IVL,   ivl ) #     server L3-helper Heartbeats
    aPUB.setsockopt(    zmq.HEARTBEAT_TTL,   ttl ) #     server L3-helper Heartbeats
    aPUB.setsockopt(    zmq.INVERT_MATCHING, 1 )   #   avoid server sending data back
    aPUB.setsockopt(    zmq.IMMEDIATE,       1 )   # avoid Queueing for dead-ends
    aPUB.setsockopt(    zmq.TOS,             tos ) # allow for L3-router TOS-policies
    ...
    #PUB PERFORMANCE & RESOURCES TWEAKING DETAILS GO WAY BEYOND THE SCOPE OF THIS POST
    aPUB.bind(   "tcp://*:5557" )                  # expose AccessPoint on tcp://
    
    #PULL --------------------------------------------------------------------------
    aPULL = aCTX.socket( zmq.PULL )
    aPULL.setsockopt(    zmq.LINGER,          0 )  # protect your server
    aPULL.setsockopt(    zmq.MAXMSGSIZE,      m )  # protect your server from DoS
    aPULL.setsockopt(    zmq.AFFINITY,        3 )  # protect your server resources
    aPULL.setsockopt(    zmq.HEARTBEAT_IVL,   ivl )#     server L3-helper Heartbeats
    aPULL.setsockopt(    zmq.HEARTBEAT_TTL,   ttl )#     server L3-helper Heartbeats
    ...
    #PULL PERFORMANCE & RESOURCES TWEAKING DETAILS GO WAY BEYOND THE SCOPE OF THIS POST
    aPULL.bind(   "tcp://*:5558" )                 # expose AccessPoint on tcp://
    ...
    
    #main loop ---------------------------------------------------------------------
    pass; notSoftFLAG = True
    while notSoftFLAG:
        NOP_SLEEP = 10                            #  set a 10 [ms] sleep in case NOP
        if aPULL.poll( 0 ):                       #  NEVER block/wait
           aMSG = aPULL.recv( zmq.DONTWAIT )      #  NEVER .recv()-s own data back
           #CPY = zmq_msg_copy( &aMSG );          // WARNING ABOUT NATIVE C-API
           #                                      // HANDLING, NEED .COPY()
           #                                      //           NEED .CLOSE()
           aPUB.send( aMSG,   zmq.DONTWAIT )      #  re-PUB-lish to all others but sender
           ...< process aMSG payload on server-side, if needed >...
    
           NOP_SLEEP = 0                          # !NOP, avoid 10[ms] NOP-loop sleep
           pass
    
        if aReasonToFlagLoopEXIT:
           notSoftFLAG = False
           ...
           NOP_SLEEP = 0
           pass
    
        if ...:
           ...
           pass
    
        sleep( NOP_SLEEP )                        # a soft-real-time controlled sleep on NOP
    #main loop ---------------------------------------------------------------------
    pass
    
    #########
    # ALWAYS:
    #          better using context-aware try:/except:/finally:
    
    aRetCODE = [ aSOCK.close() for aSOCK in ( aPUB, aPULL, ) ]
    ...
    
    aCTX.term()
    #   .term()
    #########
    

提交回复
热议问题