I'm currently trying to setup a ZMQ-based system in LabVIEW and came across the "The Asynchronous Client/Server Pattern" pattern (https://zguide.zeromq.org/docs/chapter3/#The-Asynchronous-Client-Server-Pattern).
It seems logical to me, but implementation-wise, I'm having a hard time, wrapping my head around it.
Does anyone have some kind of example with this or a similar pattern?
The system:
cRIO which acts as server and gets commands from multiple clients, that connect and disconnect randomly.
Sometimes they talk to the cRIO-Server at the same time and the commands come from both clients.
Thanks!
Cheers
Niels Göran
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Quick follow-up:
Since the LVZMQ lib is compiled with the draft option, I would assume that the SERVER-CLIENT pattern works. Is that correct?
I couldn't find any corresponding functions like "send" with "routing_id"..
Is this hidden somewhere or not yet implemented?
Thanks!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi,
For particular sockets like ROUTER/DEALER, the routing_id is the first part of a multipart message. This is how a ROUTER server can ensure that a response gets delivered to the correct client when it managing multiple connections simultaneously. This is called the message "envelope" and is described here: https://zguide.zeromq.org/docs/chapter3/#The-Simple-Reply-Envelope, in particular figures 28 and 29.
The idea is that you receive a multipart message which starts with the identity blob, process the rest of the message, and then send the response using that identity blob at the start. I see there's no example VI yet that shows how this works, but I should be able to throw one together when I get some spare time.
Cheers,
Martijn
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
thanks for your answer!
I came across the message envelope, but also, since the lib is compiled (can be compiled) with DRAFT enabled, I found the SERVER / CLIENT pattern, which is considered an "non-blocing" version of the ROUTER / DEALER pattern.
I changed the "zmq_labview.c" file as follows by adding a recv_server function:
EXPORTintlvzmq_recv_server(sock_obj**pinstdata,sock_obj*sockobj,UHandleh,int*flags,unsignedint*msg_routing_id){intret=0;zmq_msg_tmsg;void*sock;DSSetHSzClr(h,4);/* clear the output handle */CHECK_SOCK(sockobj);/* is this already blocking? */if(sockobj->flags&FLAG_BLOCKING)return-EINPROGRESS;sock=sockobj->sock;/* create a message object */zmq_msg_init(&msg);/* prepare for blocking call */if(pinstdata)*pinstdata=sockobj;sockobj->flags|=FLAG_BLOCKING;DEBUGMSG("RECV on %p into %p",sockobj->sock,h);ret=zmq_msg_recv(&msg,sock,flags?*flags:0);DEBUGMSG(" RECV ret %d",ret);sockobj->flags&=~FLAG_BLOCKING;/* was the call terminated? */if((ret<0)&&(zmq_errno()==ETERM)){/* if it was an interrupt, we MUST close */DEBUGMSG("TERM during RECV on %p",sockobj->sock);if(sockobj->ctx)if(sockobj->ctx->flags&FLAG_INTERRUPT)lvzmq_close(sockobj,1);if(flags)*flags=0;/* make sure flags=0 for zmq_recv_multi */zmq_msg_close(&msg);/* prevent memory leak */return-ETERM;}if(pinstdata)*pinstdata=NULL;/* is there more to the message? */if(flags)*flags=(zmq_msg_more(&msg)>0);/* was it success? */if(ret>=0){intl=(int)zmq_msg_size(&msg);DSSetHandleSize(h,l+4);*(u32*)*h=l;memcpy(*h+4,zmq_msg_data(&msg),l);// Obtain msg_routing_id from SERVER-CLIENT socket pattern*msg_routing_id=zmq_msg_routing_id(&msg);}zmq_msg_close(&msg);returnRET0(ret);}
That seems to work, since I get a number != 0 for the msg_routing_id.
But...
I also added the following "send_server" function, which has the msg_routing_id as an input and sets this for the message prior to sending.
Unfortunately, this always return with "EHOSTUNREACH: No route to host"..
I'm not sure, what's wrong here, but maybe you can give me some pointers...
I also added the corresponding VIs, I created, maybe something is wrong there..
(not much experience with calling C libs on Linux-RT 64-bit)
Next step would be to try to get the "ret_routing_id" out and back to LabVIEW for some debugging...
Hi,
Sorry I didn't get around to looking at this more, I have been swamped with work the past few months. I haven't worked with any options since DRAFT was added, as there is additional complexity there. My understanding of ZMQ paradigms probably counts as "classic" now, since those are the network structures that led me to wrap the library in the first place. The paradigms can be a bit confusing, particularly as the example implementations tend to use blocking calls. Hope you were able to work something out.
Cheers,
Martijn
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
unfortunately I haben't made any progress whatsoever in the last months due to work.
I still need to perform that debugging mentioned.
Nevertheless, I think, that I will for now adhere to Request-Reply and just handle connection after each other.
Any other ideas are welcome ;-)
Cheers
Niels
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello everyone,
I'm currently trying to setup a ZMQ-based system in LabVIEW and came across the "The Asynchronous Client/Server Pattern" pattern (https://zguide.zeromq.org/docs/chapter3/#The-Asynchronous-Client-Server-Pattern).
It seems logical to me, but implementation-wise, I'm having a hard time, wrapping my head around it.
Does anyone have some kind of example with this or a similar pattern?
The system:
cRIO which acts as server and gets commands from multiple clients, that connect and disconnect randomly.
Sometimes they talk to the cRIO-Server at the same time and the commands come from both clients.
Thanks!
Cheers
Niels Göran
Quick follow-up:
Since the LVZMQ lib is compiled with the draft option, I would assume that the SERVER-CLIENT pattern works. Is that correct?
I couldn't find any corresponding functions like "send" with "routing_id"..
Is this hidden somewhere or not yet implemented?
Thanks!
Hi,
For particular sockets like ROUTER/DEALER, the routing_id is the first part of a multipart message. This is how a ROUTER server can ensure that a response gets delivered to the correct client when it managing multiple connections simultaneously. This is called the message "envelope" and is described here: https://zguide.zeromq.org/docs/chapter3/#The-Simple-Reply-Envelope, in particular figures 28 and 29.
The idea is that you receive a multipart message which starts with the identity blob, process the rest of the message, and then send the response using that identity blob at the start. I see there's no example VI yet that shows how this works, but I should be able to throw one together when I get some spare time.
Cheers,
Martijn
Hello,
thanks for your answer!
I came across the message envelope, but also, since the lib is compiled (can be compiled) with DRAFT enabled, I found the SERVER / CLIENT pattern, which is considered an "non-blocing" version of the ROUTER / DEALER pattern.
I changed the "zmq_labview.c" file as follows by adding a recv_server function:
That seems to work, since I get a number != 0 for the msg_routing_id.
But...
I also added the following "send_server" function, which has the msg_routing_id as an input and sets this for the message prior to sending.
Unfortunately, this always return with "EHOSTUNREACH: No route to host"..
I'm not sure, what's wrong here, but maybe you can give me some pointers...
I also added the corresponding VIs, I created, maybe something is wrong there..
(not much experience with calling C libs on Linux-RT 64-bit)
Next step would be to try to get the "ret_routing_id" out and back to LabVIEW for some debugging...
Thanks !
Cheers
Niels Göran
Last edit: Niels Göran Blume 2022-03-30
Hej hej,
any comments / ideas regarding this ?
Thanks !
Cheers
Niels Göran
Hi,
Sorry I didn't get around to looking at this more, I have been swamped with work the past few months. I haven't worked with any options since DRAFT was added, as there is additional complexity there. My understanding of ZMQ paradigms probably counts as "classic" now, since those are the network structures that led me to wrap the library in the first place. The paradigms can be a bit confusing, particularly as the example implementations tend to use blocking calls. Hope you were able to work something out.
Cheers,
Martijn
Hello Martijn,
unfortunately I haben't made any progress whatsoever in the last months due to work.
I still need to perform that debugging mentioned.
Nevertheless, I think, that I will for now adhere to Request-Reply and just handle connection after each other.
Any other ideas are welcome ;-)
Cheers
Niels