How to "reverse direction" of POSIX message queue in Linux?

I am trying to figure out how to "reverse" a single POSIX message queue to enable two-way communication between a client and server process while only using one POSIX message queue (i.e. only one memory segment at a time). The purpose of this is to cut memory overhead in half for IPC with many clients. This is, in essence, a half-duplex setup where two-way communication is supported, but messages can only flow in one direction at a time.

The standard approach is to use one queue for client -> server and one queue for server -> client as shown below (this is basically my current code).

Client:

1
2
3
4
5
6
7
8
9
10
11
12
...
int read = mq_open("servertoclient", O_RDWR | O_CREAT, 0600, 0);
int write = mq_open("clienttoserver", O_RDWR | O_CREAT, 0600, 0);
char send_buffer[8192];
mq_send(write, send_buffer, 8192, 0); //send message to server
char receive_buffer[8192];
mq_receive(read, receive_buffer, 8192, 0); //receive response from server
mq_close(write);
mq_close(read);
mq_unlink("servertoclient");
mq_unlink("clienttoserver");
...


Server:

1
2
3
4
5
6
7
8
9
10
11
12
...
int write = mq_open("servertoclient", O_RDWR | O_CREAT, 0600, 0);
int read = mq_open("clienttoserver", O_RDWR | O_CREAT, 0600, 0);
char send_buffer[8192];
mq_send(write, send_buffer, 8192, 0); //send message to client
char receive_buffer[8192];
mq_receive(read, receive_buffer, 8192, 0); //receive response from client
mq_close(write);
mq_close(read);
mq_unlink("servertoclient");
mq_unlink("clienttoserver");
...

I am looking for a way to accomplish almost the same thing, but only using a single message queue at a time, not one for each direction simultaneously. The only difference is that with the single queue, simultaneous sending/receiving will not be supported, which is OK in my situation. Server and client will use some kind of special 'code' that signals a queue reversal. This is akin to a radio where you talk, then release the button and the receiver's radio beeps, letting them know you've finished talking. Then you listen to the receiver's message until your radio beeps. But the sender and receiver can never talk over each other.

Something along these lines:

Client:

1
2
3
4
5
6
7
8
open a single queue with mq_open for writing to the server
send some data
send a special message notifying the server that the queue is to be reversed
prepare queue for reading (not sure how to do this)
read data from server until the 'reverse' message is received, then revert queue to write
... keep going like this until a terminating message is received or client exits

unlink the queue


Server:

1
2
3
4
5
6
7
8
9
open a single queue with mq_open for reading from client
read in data
if the terminating message is read, 
   prepare queue for writing to client
send data and finish by sending the special 'reverse' message
prepare queue for reading
... keep going like this until a terminating message is received or server exits

unlink the queue


The client will always initiate the first message, so there is never any danger of the server wanting to send a message initially, for example.

I am not open to using any other method of interprocess communication (such as shared memory, sysv queues, pipes, tcp/udp, etc.).
Last edited on
Why do you want to do this?

Because the very real problem is how you would stop one end from reading the message it just wrote.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ cat foo.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>

int main ( ) {
  mqd_t rw = mq_open("/mymq", O_RDWR | O_CREAT, 0600, 0);
  char send_buffer[100] = "hello world";
  int a = mq_send(rw, send_buffer, sizeof(send_buffer), 0); //send message to server
  char receive_buffer[8192] = "";
  int b = mq_receive(rw, receive_buffer, sizeof(receive_buffer), 0); //receive response from server
  mq_close(rw);
  mq_unlink("/mymq");
  printf("%d %d %d %s\n", rw, a, b, receive_buffer);
  return 0;
}

$ ./a.out 
3 0 100 hello world


I suppose you could add a load of baggage centred on copious use of mq_getattr and mq_notify.
https://man7.org/linux/man-pages/man3/mq_setattr.3.html
https://man7.org/linux/man-pages/man3/mq_notify.3.html

EDIT:
> the purpose of this is to cut memory overhead in half for IPC with many clients.
https://man7.org/linux/man-pages/man3/mq_open.3.html
So use the long form of mq_open where you specify your own mq_msgsize of say 1024 (or whatever is good for you), rather than the default which seems like 8K.
Last edited on
Topic archived. No new replies allowed.