Interprocess communication --POSIX message queue

1. Message Queuing

Message queue with the conduit

Same point:
      With all kernel space, communicate, if not unlink, even if the process close, Message Queue will continue to exist.
      And because by means of the kernel space, there is another data copying between user space and kernel space, and consumption efficiency.
difference:
      Similarly SMS message queue, the peer need not online.
      Pipeline similar phone, the need for end-line.

 

2.API

(1)mq_open

       mqd_t mq_open(const char *name, int oflag);
       mqd_t mq_open(const char *name, int oflag, mode_t mode,
                     struct mq_attr *attr);

mq_open() creates a new POSIX message queue or opens an existing queue.

flag must value

O_RDONLY, O_WRONLY, O_RDWR

flag optional value

O_CLOEXEC, O_CREAT, O_EXCL, O_UNBLOCK
O_CREAT:
      If the message queue does not exist, then create a new, or has no effect, equivalent to open
O_EXCL
      Must be used in conjunction with O_CREAT, if the message queue already exists, returns an error, errno = EEXIST
O_NONBLOCK
      Read the message queue, the default is blocked, i.e.,
           send, if the queue is full will be blocked,
           When recv, if the queue is empty, will be blocked.
      Setting the O_NONBLOCK, if abnormal, the process directly returns an error, errno = EAGAIN

attr set the queue parameters, attr == NULL or the default parameters.

(2)mq_receive

       ssize_t mq_receive(mqd_t mqdes, char *msg_ptr,
                          size_t msg_len, unsigned int *msg_prio);

       #include <time.h>
       #include <mqueue.h>

       ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr,
                          size_t msg_len, unsigned int *msg_prio,
                          const struct timespec *abs_timeout);
The highest priority, oldest news from the team,
Output in msg_ptr,
msg_len the specified len msg_ptr,
msg_len must be greater than the size of the message queue entries (obtained by mq_getattr)
If the queue is empty,
The default block until not empty, or signal interruption (returns an error, errno == EINTR),
Set O_NONBLOCK, direct returns an error (errno == EAGAIN),
Use mq_timedreceive, you can set the blocking time (absolute time)
return value:
      It returns the number of bytes successfully received

 

(3)mq_getattr

       int mq_getattr(mqd_t mqdes, struct mq_attr *attr);

       int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr,
                        struct mq_attr *oldattr);
           struct mq_attr {
               long mq_flags;       /* Flags: 0 or O_NONBLOCK */
               long mq_maxmsg;      /* Max. # of messages on queue */
               long mq_msgsize;     /* Max. message size (bytes) */
               long mq_curmsgs;     /* # of messages currently in queue */
           };

When new queue mq_attr are initialized.

mq_flags
        Only display 0 or O_NONBLOCK
mq_maxmsg
        Queue up to the number of messages
mq_msgsize
        The maximum length of the message queue
mq_curmsgs
        The current number of messages queue

mq_setattr can only be set mq_flags add O_NONBLOCK

(4)mq_close

       int mq_close(mqd_t mqdes);

Close message queue descriptor.

And close the notification request is turned on, so that other threads can apply for notification request.

Auto Close message queue descriptor at the end of the process or exec.

(5)mq_unlink

       mqd_t mq_unlink(const char *name);

Remove the message queue name,

When the queue is open all processes have closed the queue, the queue themselves destroyed.

 

3. Application

(A) receiving simple

#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>

#define MQ_NAME         "/mq_test"

int main ()
{
        struct          mq_attr attr = {0};
        mqd_t mqid;
        int             mq_len = 60, bytes;
        char            *buf;

        attr.mq_msgsize = mq_len;
        attr.mq_maxmsg = 10 ;

__again_open__:
        if (0 > (mqid = mq_open("/mq_test", O_RDONLY | O_CREAT | O_EXCL, 0777, &attr))) {

                if (errno == EEXIST) {
                        mq_unlink(MQ_NAME);
                        goto __again_open__;
                }

                perror("mq_open");
                return -1;
        }

        if (0 > (buf = (char *)malloc(mq_len))) {
                perror("malloc");
                return -1;
        }
__again_recv__:
        if (0 > (bytes = mq_receive(mqid, buf, mq_len, NULL))) {

                if (errno == EINTR)
                        goto __again_recv__;
                perror("mq_receive");
                return -1;
        }
        printf("recv %d bytes : %s\n", bytes, buf);
        goto __again_recv__;


        return 0;
}

(2) simply send

#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>

#define MQ_NAME                 "/mq_test"

int main(int argc, char **argv)
{
        int             bytes, msg_len;
        mqd_t mqid;
        struct mq_attr  attr;
        char            *msg = argv[1];

        if (0 > (mqid = mq_open(MQ_NAME, O_WRONLY | O_NONBLOCK))) {
                perror("mq_open");
                return -1;
        }

__again__:
        if (0 > (bytes = mq_send(mqid, msg, strlen(msg), 10))) {
                if (errno == EAGAIN) {
                        usleep(100);
                        goto __again__;
                }
                perror("mq_send");
                return -1;
        }
        printf("success to send %d bytes\n", bytes);

        return 0;
}

 

-------------- POSIX message queue and an asynchronous notification

POSIX message queues with respect to different queues SystemV important message:

          POSIX message queues and thread support asynchronous notification signal.

1.API

       mqd_t mq_notify (mqd_t mqdes, const  struct sigevent notification *);

Thread or revoke a registration for message notification.

           union sigval {          /* Data passed with notification */
               int     sival_int;         /* Integer value */
               void   *sival_ptr;         /* Pointer value */
           };

           struct sigevent {
               int          sigev_notify; /* Notification method */
               int          sigev_signo;  /* Notification signal */
               union sigval sigev_value;  /* Data passed with
                                             notification */
               void       (*sigev_notify_function) (union sigval);
                                          /* Function for thread
                                             notification */
               void        *sigev_notify_attributes;
                                          /* Thread function attributes */
           };
sigev_notify
          It is used to specify notification method
          SIGEV_NONE, specify this thread to accept the notice, but after the incident, will not be notified
          SIGEV_SIGNAL: Use signaling
          SIGEV_THREAD: Use thread notifies
sigev_signo
          If signaling, it is used to specify notification signal
sigev_value
          If signaled, and the SA_SIGINFO sigaction specified, the reference for the signal transmission
          If a thread notification, the thread used for mass participation
sigev_notify_function:
          Specify the thread start function
sigev_notify_atrributes: 
          Specified thread property, set using pthread_attr_init
Only one thread / Register notice on the process.
Only when the message queue is empty, when the team news, release notification.
A registration notification, the notification will only once, after the notification is removed.
When the message queue is blocking state, and there are processes or threads are recv, namely blocking In the above is not sent notification (recommended NONBLOCK queue).

3. Application

       #include <pthread.h>
       #include <mqueue.h>
       #include <assert.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <unistd.h>

       #define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

       static void                     /* Thread start function */
       tfunc (union Sigvatur sv)
       {
           struct mq_attr attr;
           ssize_t nr;
           void *buf;
           mqd_t mqdes = * ((* mqd_t ) sv.sival_ptr);

           /* Determine max. msg size; allocate buffer to receive msg */

           if (mq_getattr(mqdes, &attr) == -1)
               handle_error("mq_getattr");
           buf = malloc(attr.mq_msgsize);
           if (buf == NULL)
               handle_error("malloc");

           nr = mq_receive(mqdes, buf, attr.mq_msgsize, NULL);
           if (nr == -1)
               handle_error("mq_receive");

           printf("Read %ld bytes from MQ\n", (long) nr);
           free(buf);
           exit(EXIT_SUCCESS);         /* Terminate the process */
       }

       int
       main(int argc, char *argv[])
       {
           mqd_t mqdes;
           struct sigevent not;

           assert(argc == 2);

           mqdes = mq_open(argv[1], O_RDONLY);
           if (mqdes == (mqd_t) -1)
               handle_error("mq_open");

           not.sigev_notify = SIGEV_THREAD;
           not.sigev_notify_function = tfunc;
           not.sigev_notify_attributes = NULL;
           not.sigev_value.sival_ptr = &mqdes;   /* Arg. to thread func. */
           if (mq_notify(mqdes, &not) == -1)
               handle_error("mq_notify");

           pause();    /* Process will be terminated by thread function */
       }
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>

#define MQ_NAME                 "/mq_test"

int g_catch_usr1_flag;

void catch_usr1(int sig)
{
        g_catch_usr1_flag = 1;
}


int main ()
{
        int                     msg_len = 256, bytes;
        struct mq_attr          attr;
        mqd_t mqid;
        struct sigevent         notification;
        struct sigaction        act;
        char                    msg[msg_len + 1];

        attr.mq_maxmsg = 10 ;
        attr.mq_msgsize = msg_len;

__try_open__:
        if (0 > (mqid = mq_open(MQ_NAME, O_RDONLY | O_CREAT | O_EXCL | O_NONBLOCK, 0777, &attr))) {
                if (errno == EEXIST) {
                        if (0 > mq_unlink(MQ_NAME)) {
                                perror("mq_unlink");
                                return -1;
                        }
                        goto __try_open__;
                }
                perror("mq_open");
        }


        signal(SIGUSR1, catch_usr1);

        notification.sigev_notify = SIGEV_SIGNAL;
        notification.sigev_signo = SIGUSR1;
        if (0 > mq_notify(mqid, &notification)) {
                perror("mq_notify");
                return -1;
        }

        while (1) {

                if (0 == g_catch_usr1_flag) {
                        usleep(300);
                        continue;
                }
                g_catch_usr1_flag = 0;
                if (0 > mq_notify(mqid, &notification)) {
                        perror("mq_notify");
                        return -1;
                }

                if (0 > (bytes = mq_receive(mqid, msg, msg_len, NULL))) {
                        perror("mq_receive");
                        return -1;
                }
                msg[bytes] = 0;

                printf("recv %d bytes : %s\n", bytes, msg);
        }


        return 0;
}

Guess you like

Origin www.cnblogs.com/yangxinrui/p/12071107.html