How to set up a ZeroMQ request-reply between a c# and python application

1.4k views Asked by At

I'm trying to communicate between a c#(5.0) and a python (3.9) application via ZeroMQ. For .Net I'm using NetMQ and for python PyZMQ.

I have no trouble letting two applications communicate, as long as they are in the same language

  • c# app to c# app;
  • python -> python;
  • java -> java,

but trouble starts when I try to connect between different languages.

  • java -> c# and reverse works fine as well [edited]

I do not get any errors, but it does not work either.

I first tried the PUB-SUB Archetype pattern, but as that didn't work, I tried REQ-REP, so some remainders of the "PUB-SUB"-version can still be found in the code.

My Python code looks like this :

def run(monitor: bool):
loop_counter: int = 0

context = zmq.Context()
# socket = context.socket(zmq.PUB)
# socket.bind("tcp://*:5557")
socket = context.socket(zmq.REP)
socket.connect("tcp://localhost:5557")

if monitor:
    print("Connecting")

# 0 = Longest version, 1 = shorter version, 2 = shortest version
length_version: int = 0

print("Ready and waiting for incoming requests ...")

while True:
    message = socket.recv()

    if monitor:
        print("Received message:", message)

    if message == "long":
        length_version = 0
    elif message == "middle":
        length_version = 1
    else:
        length_version = 2

    sys_info = get_system_info(length_version)

    """if not length_version == 2:
        length_version = 2

    loop_counter += 1

    if loop_counter == 15:
        length_version = 1

    if loop_counter > 30:
        loop_counter = 0
        length_version = 0"""

    if monitor:
        print(sys_info)

    json_string = json.dumps(sys_info)
    print(json_string)
    socket.send_string(json_string)

My C# code :

static void Main(string[] args)
    {
        //using (var requestSocket = new RequestSocket(">tcp://localhost:5557"))
        using (var requestSocket = new RequestSocket("tcp://localhost:5557"))    
        {
            while (true) {
                Console.WriteLine($"Running the server ...");
                string msg = "short";
                requestSocket.SendFrame(msg);
                var message = requestSocket.ReceiveFrameString();
                Console.WriteLine($"requestSocket : Received '{message}'");
                //Console.ReadLine();
                Thread.Sleep(1_000);
            }
        }
    }
3

There are 3 answers

1
totoleroi On BEST ANSWER

Seeing the period of your problems maybe it's because of versions. I run fine a program for long time with communications from Windows/C# with NTMQ 4.0.0.207 239,829 7/1/2019 on one side and Ubuntu/Python with zeromq=4.3.1 and pyzmq=18.1.0. I just tried updating to use same NETMQ version but with new versions zeromq=4.3.3 and pyzmq=20.0.0 but there is a problem/bug somewhere and it doesn't run well anymore.

So your code doesn't look bad may be it's software versions issues not doing well try with NTMQ 4.0.0.207 on c# side and zeromq=4.3.1 with pyzmq=18.1.0 on python side

3
user3666197 On

Q : "How to set up a ZeroMQ request-reply between a c# and python application"

The problem starts with the missed understanding of how REQ/REP archetype works.

Your code uses a blocking-form of the .recv()-method, so you remain yourselves hanging Out-of-the-Game, forever & unsalvageable, whenever a REQ/REP two-step gets into troubles (as no due care was taken to prevent this infinite live-lock).

Rather start using .poll()-method to start testing a presence / absence of a message in the local AccessNode-side of the queue and this leaves you in a capability to state-fully decide what to do next, if a message is already or is not yet present, so as to keep the mandatory sequence of an API-defined need to "zip" successful chainings of
REQ-side .send()-.recv()-.send()-.recv()-... with
REP-side .recv()-.send()-.recv()-.send()-... calls, are the REQ/REP archetype works as a distributed-Finite-State-Automaton (dFSA), that may easily deadlock itself, due to "remote"-side not being compliant with the local-side expectations.

Having a code, that works in a non-blocking, .poll()-based mode avoids falling into these traps, as you may handle each of these unwanted circumstances while being still in a control of the code-execution paths (which a call to a blocking-mode method in a blind belief it will return at some future point in time, if ever, simply is not capable of).

Q.E.D.


If in doubts, one may use a PUSH/PULL archetype, as the PUB/SUB-archetype may run into problems with non-matching subscriptions ( topic-list management being another, version dependent detail ).

There ought be no other problem for any of the language-bindings, if they passed all the documented ZeroMQ API features without creating any "shortcuts" - some cases were seen, where language-specific binding took "another" direction for PUB/SUB, when sending a pure message, transformed into a multi-part message, putting a topic into a first frame and the message into the other. That is an example of a binding not compatible with the ZeroMQ API, where a cross-language / non-matching binding-version system problems are clear to come.

0
Oggie On

I might be late, but this same thing happened to me. I have a python Subscriber using pyzmq and a C# Publisher using NetMQ.

After a few hours, it occurred to me that I needed to let the Publisher some time to connect. So a simple System.Threading.Thread.Sleep(500); after the Connect/Bind did the trick.