title:Mqueue IPC example in shell script
keywords:bash,linux,mqueue,ipc
# Mqueue IPC example in shell script
## Intro
Idea of messages comes from beginning of computer history. Mainly used for inter-process
communication. Fascinating fact is no I havent seen someone using them on linux.
Using mqueue is probably most easiest IPC interface possible. Cool feature of it it have
path where you can access it. And as its act as queue then you can just open/read message
with minimal amount of code. Disadvantage is you don't know who sent you message.
Advantages
* simple API
* no need to verify message size, comes as single packet
* persistent, if one program crashed, message stays in queue
Disadvantages:
* cant be sure to who received message
* bidirectional communication could be harder to implement
One of bash hacks that can be archived is inter process communication between
two bash scripts. Example will be provided!
## Linux mqueue API
Most system have them compiled in kernel you can check if you system supports them
```bash
$ cat /proc/filesystems | grep mq
nodev mqueue
```
and if its mounted with
```bash
$ mount | grep mque
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
```
API for using mqueue is similar all UNIX interface. To check status of mqueue
use cat command
```bash
$ cat /dev/mqueue/stack-0
QSIZE:0 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
```
Further is mentioned API calls and API usage template.
### Library interfaces and system calls
Library interface System call
mq_close(3) close(2)
mq_getattr(3) mq_getsetattr(2)
mq_notify(3) mq_notify(2)
mq_open(3) mq_open(2)
mq_receive(3) mq_timedreceive(2)
mq_send(3) mq_timedsend(2)
mq_setattr(3) mq_getsetattr(2)
mq_timedreceive(3) mq_timedreceive(2)
mq_timedsend(3) mq_timedsend(2)
mq_unlink(3) mq_unlink(2)
### Create mqueue
Mqueue are located in mount point directory. Check with mount command where its located.
Majority system have it at /dev/mqueue .
Mqueue names passed to API should start with "/" no mount point path name needed in front.
Create mqueue by opening it
```c
mq_open("/name",O_RDWR | O_CREAT, 0666, NULL);
```
### Send mqueue message
If mqueue already created then it will be opened, otherwise created.
```c
mq_open("/name",O_RDWR | O_CREAT, 0666, NULL);
mq_send(fd, "packet", strlen("packet"), set_mesg_priority);
```
### Receive mqueue message
If mqueue already created then it will be opened, otherwise created
```c
mq_open("/name",O_RDWR | O_CREAT, 0666, NULL);
mq_receive(mq_fd, ptr_to_str, ptr_size, &get_priority);
```
### Remove mqueue
Unlink file, path will disappear after all process will release file descriptors,
after unlink.
```c
mq_open("/name",O_RDWR | O_CREAT, 0666, NULL);
mq_unlink("/name");
```
## Example bash IPC
Further is source of utilities for using mqueues. Lets create example where
one message queue created from one script, and script loops over and check
received messages from queue, and executes received commands.
### Server script that check mqueue for commands
loop reads queue with "./mqueue_pop -m QUEUE_NAME". If its successful
then it receives non-empty string, if not then string is empty.
Create queue if its not there with "./mqueue_create -m $QUEUE_NAME".
And after receiving stop command exits loops and unlink queue.
3 commands supported to be sent stop/ls/aloha
_daemon.sh_
```bash
#!/bin/sh
QUEUE_NAME=/music-player-daemon
POP_CMD()
{
./mqueue_pop -m $QUEUE_NAME
}
CREATE_QUEUE()
{
./mqueue_create -m $QUEUE_NAME
}
REMOVE_QUEUE()
{
./mqueue_remove -m $QUEUE_NAME
}
if [ ! -f "/dev/mqueue$QUEUE_NAME" ]; then
CREATE_QUEUE
fi
state="1"
while [ $state -ne 0 ]; do
get_cmd=$(POP_CMD)
case "$get_cmd" in
stop)
state="0"
;;
ls)
ls /dev
;;
aloha)
echo "aloha"
;;
esac
sleep 1
done
if [ -f "/dev/mqueue$QUEUE_NAME" ]; then
REMOVE_QUEUE
fi
```
### Send commands to script
Send commands to running server script. First lists /dev directory,
second output aloha and third one terminates script.
```
./send_command ls
./send_command aloha
./send_command stop
```
_send_command.sh_
```bash
#!/bin/sh
QUEUE_NAME=/music-player-daemon
SEND_CMD()
{
./mqueue_push -m $QUEUE_NAME -p "$1"
}
echo "Send command to daemon"
if [ -f "/dev/mqueue$QUEUE_NAME" ]; then
SEND_CMD $1
else
echo "No queue to send"
fi
```
## Source of example utilities for using mqueue
All source located at [http://git.main.lv/cgit.cgi/mqueue_examples.git/](http://git.main.lv/cgit.cgi/mqueue_examples.git/)
When compiling **-lrt** flag required
### mqueue_create.c - Create mqueue
_mqueue_create.c_
```c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <mqueue.h>
#include <errno.h>
typedef struct {
char *f_mqname;
int f_verbose;
int f_helper;
} mqueue_params;
mqueue_params g_params;
void helper(char *progname)
{
printf("Usage: %s [OPTS]\n\n"
"Version: 0.0.1 \n"
"-m mqueue name\n"
"-v verbose output\n"
"-h help options\n"
"\n"
, progname);
}
#define full_mqpath_len 1024
int main(int argc, char **argv)
{
//stack params
int c,err;
int i;
int mq_fd;
char full_mqpath[full_mqpath_len];
memset(&g_params,0,sizeof(g_params));
//process arguments
while ((c = getopt(argc, argv, "m:vh")) != -1)
{
switch (c)
{
case 'm':
g_params.f_mqname = optarg;
break;
case 'v':
g_params.f_verbose = 1;
break;
case 'h':
default:
helper(argv[0]);
exit(1);
}
}
if (g_params.f_helper)
{
helper(argv[0]);
return 0;
}
//set mqueue name
if (g_params.f_mqname == NULL)
{
g_params.f_mqname = "/stack-0";
}
//compose string
memset(&full_mqpath[0], 0, full_mqpath_len);
snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname);
if (g_params.f_verbose)
{
printf("Full path: %s\n",&full_mqpath);
}
mq_fd = mq_open(g_params.f_mqname,O_RDWR | O_CREAT, 0666, NULL);
err = errno;
if (mq_fd == -1)
{
if (g_params.f_verbose)
{
printf("ERROR:%d,%s\n",err,strerror(err));
}
return -1;
}
printf("%s\n",g_params.f_mqname);
close(mq_fd);
return 0;
}
```
### mqueue_push.c - Push values to mqueue
_mqueue_push.c_
```c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <mqueue.h>
#include <errno.h>
typedef struct {
char *f_mqname;
char *f_push;
int f_verbose;
int f_helper;
} mqueue_params;
mqueue_params g_params;
void helper(char *progname)
{
printf("Usage: %s [OPTS] VALUE\n\n"
"Version: 0.0.1 \n"
"-m mqueue name\n"
"-v verbose output\n"
"-p push value\n"
"-h help options\n"
"\n"
, progname);
}
#define full_mqpath_len 1024
int main(int argc, char **argv)
{
//stack params
int c,err;
int i;
int mq_fd;
char full_mqpath[full_mqpath_len];
int prio=10;
char *push_val="NONE";
int push_size=strlen(push_val);
memset(&g_params,0,sizeof(g_params));
//process arguments
while ((c = getopt(argc, argv, "m:vhp:")) != -1)
{
switch (c)
{
case 'm':
g_params.f_mqname = optarg;
break;
case 'v':
g_params.f_verbose = 1;
break;
case 'p':
g_params.f_push = optarg;
break;
case 'h':
default:
helper(argv[0]);
exit(1);
}
}
if (g_params.f_helper)
{
helper(argv[0]);
return 0;
}
//set mqueue name
if (g_params.f_mqname == NULL)
{
g_params.f_mqname = "/stack-0";
}
//compose string
memset(&full_mqpath[0], 0, full_mqpath_len);
snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname);
if (g_params.f_verbose)
{
printf("Full path: %s\n",&full_mqpath);
}
mq_fd = mq_open(g_params.f_mqname,O_RDWR | O_CREAT, 0666, NULL);
err = errno;
if (mq_fd == -1)
{
if (g_params.f_verbose)
{
printf("ERROR:%d,%s\n",err,strerror(err));
}
return -1;
}
printf("%s\n",g_params.f_mqname);
if (g_params.f_push != NULL)
{
push_val = g_params.f_push;
push_size = strlen(push_val);
}
mq_send(mq_fd, push_val, push_size, prio);
close(mq_fd);
return 0;
}
```
### mqueue_pop.c - Get value from mqueue
_mqueue_pop.c_
```c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <mqueue.h>
#include <errno.h>
typedef struct {
char *f_mqname;
int f_verbose;
int f_helper;
} mqueue_params;
mqueue_params g_params;
void helper(char *progname)
{
printf("Usage: %s [OPTS] VALUE\n\n"
"Version: 0.0.1 \n"
"-m mqueue name\n"
"-v verbose output\n"
"-h help options\n"
"\n"
, progname);
}
#define full_mqpath_len 1024
int main(int argc, char **argv)
{
//stack params
int ret=0;
int c,err;
int i;
int mq_fd;
char full_mqpath[full_mqpath_len];
int prio;
struct mq_attr attr;
char *pop_val=NULL;
int pop_size;
memset(&g_params,0,sizeof(g_params));
//process arguments
while ((c = getopt(argc, argv, "m:vh")) != -1)
{
switch (c)
{
case 'm':
g_params.f_mqname = optarg;
break;
case 'v':
g_params.f_verbose = 1;
break;
case 'h':
default:
helper(argv[0]);
exit(1);
}
}
if (g_params.f_helper)
{
helper(argv[0]);
return 0;
}
//set mqueue name
if (g_params.f_mqname == NULL)
{
g_params.f_mqname = "/stack-0";
}
//compose string
memset(&full_mqpath[0], 0, full_mqpath_len);
snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname);
if (g_params.f_verbose)
{
printf("Full path: %s\n",&full_mqpath);
}
mq_fd = mq_open(g_params.f_mqname,O_RDWR | O_CREAT, 0666, NULL);
err = errno;
if (mq_fd == -1)
{
if (g_params.f_verbose)
{
printf("ERROR:%d,%s\n",err,strerror(err));
}
return -1;
}
//printf("%s\n",g_params.f_mqname);
mq_getattr(mq_fd, &attr);
pop_val = malloc(attr.mq_msgsize+1);
memset(pop_val, 0, attr.mq_msgsize+1);
if (attr.mq_curmsgs > 0)
{
pop_size = mq_receive(mq_fd, pop_val, attr.mq_msgsize, &prio);
printf("%s\n",pop_val);
} else {
ret = -1;
}
close(mq_fd);
free(pop_val);
return ret;
}
```
### mqueue_remove.c - Remove mqueue
_mqueue_remove.c_
```c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <mqueue.h>
#include <errno.h>
typedef struct {
char *f_mqname;
int f_verbose;
int f_helper;
} mqueue_params;
mqueue_params g_params;
void helper(char *progname)
{
printf("Usage: %s [OPTS] VALUE\n\n"
"Version: 0.0.1 \n"
"-m mqueue name\n"
"-v verbose output\n"
"-h help options\n"
"\n"
, progname);
}
#define full_mqpath_len 1024
int main(int argc, char **argv)
{
//stack params
int ret=0;
int c,err;
int i;
int mq_fd;
char full_mqpath[full_mqpath_len];
memset(&g_params,0,sizeof(g_params));
//process arguments
while ((c = getopt(argc, argv, "m:vh")) != -1)
{
switch (c)
{
case 'm':
g_params.f_mqname = optarg;
break;
case 'v':
g_params.f_verbose = 1;
break;
case 'h':
default:
helper(argv[0]);
exit(1);
}
}
if (g_params.f_helper)
{
helper(argv[0]);
return 0;
}
//set mqueue name
if (g_params.f_mqname == NULL)
{
g_params.f_mqname = "/stack-0";
}
//compose string
memset(&full_mqpath[0], 0, full_mqpath_len);
snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname);
if (g_params.f_verbose)
{
printf("Full path: %s\n",&full_mqpath);
}
mq_unlink(g_params.f_mqname);
close(mq_fd);
return ret;
}
```
### mqueue_info.c - Get stats from mqueue
_mqueue_info.c_
```c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <mqueue.h>
#include <errno.h>
typedef struct {
char *f_mqname;
int f_verbose;
int f_helper;
} mqueue_params;
mqueue_params g_params;
void helper(char *progname)
{
printf("Usage: %s [OPTS] VALUE\n\n"
"Version: 0.0.1 \n"
"-m mqueue name\n"
"-v verbose output\n"
"-h help options\n"
"\n"
, progname);
}
#define full_mqpath_len 1024
int main(int argc, char **argv)
{
//stack params
int ret=0;
int c,err;
int i;
int mq_fd;
char full_mqpath[full_mqpath_len];
int prio;
struct mq_attr attr;
char *pop_val=NULL;
int pop_size;
memset(&g_params,0,sizeof(g_params));
//process arguments
while ((c = getopt(argc, argv, "m:vh")) != -1)
{
switch (c)
{
case 'm':
g_params.f_mqname = optarg;
break;
case 'v':
g_params.f_verbose = 1;
break;
case 'h':
default:
helper(argv[0]);
exit(1);
}
}
if (g_params.f_helper)
{
helper(argv[0]);
return 0;
}
//set mqueue name
if (g_params.f_mqname == NULL)
{
g_params.f_mqname = "/stack-0";
}
//compose string
memset(&full_mqpath[0], 0, full_mqpath_len);
snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname);