Linux-Message Queue programming instance

Source: Internet
Author: User

The above is the compilation of the project under eclipse. The code is from 《Praise for the Linux Programming Interface. It consists of three files.

/*************************************************************************\*                  Copyright (C) Michael Kerrisk, 2010.                   **                                                                         ** This program is free software. You may use, modify, and redistribute it ** under the terms of the GNU Affero General Public License as published   ** by the Free Software Foundation, either version 3 or (at your option)   ** any later version. This program is distributed without any warranty.    ** See the file COPYING.agpl-v3 for details.                               *\*************************************************************************//* Listing 46-7 */#include <sys/types.h>#include <sys/msg.h>#include <sys/stat.h>#include <stddef.h>                     /* For definition of offsetof() */#include <stdarg.h>                     /* For definition of offsetof() */#include <limits.h>#include <fcntl.h>#include <signal.h>#include <sys/wait.h>#include <sys/types.h>  /* Type definitions used by many programs */#include <stdio.h>      /* Standard I/O functions */#include <stdlib.h>     /* Prototypes of commonly used library functions,                           plus EXIT_SUCCESS and EXIT_FAILURE constants */#include <unistd.h>     /* Prototypes for many system calls */#include <errno.h>      /* Declares errno and defines error constants */#include <string.h>     /* Commonly used string-handling functions */#define SERVER_KEY 0x1aaaaaa1           /* Key for server's message queue */struct requestMsg {                     /* Requests (client to server) */    long mtype;                         /* Unused */    int  clientId;                      /* ID of client's message queue */    char pathname[PATH_MAX];            /* File to be returned */};/* REQ_MSG_SIZE computes size of 'mtext' part of 'requestMsg' structure.   We use offsetof() to handle the possibility that there are padding   bytes between the 'clientId' and 'pathname' fields. */#define REQ_MSG_SIZE (offsetof(struct requestMsg, pathname) - \                      offsetof(struct requestMsg, clientId) + PATH_MAX)#define RESP_MSG_SIZE 8192struct responseMsg {                    /* Responses (server to client) */    long mtype;                         /* One of RESP_MT_* values below */    char data[RESP_MSG_SIZE];           /* File content / response message */};/* Types for response messages sent from server to client */#define RESP_MT_FAILURE 1               /* File couldn't be opened */#define RESP_MT_DATA    2               /* Message contains file data */#define RESP_MT_END     3               /* File data complete */typedef enum { FALSE, TRUE } Boolean;#define min(m,n) ((m) < (n) ? (m) : (n))#define max(m,n) ((m) > (n) ? (m) : (n))static void outputError(Boolean useErr, int err, Boolean flushStdout,const char *format, va_list ap);static void terminate(Boolean useExit3);void usageErr(const char *format, ...);void cmdLineErr(const char *format, ...);void errExit(const char *format, ...);

/*************************************************************************\*                  Copyright (C) Michael Kerrisk, 2010.                   **                                                                         ** This program is free software. You may use, modify, and redistribute it ** under the terms of the GNU Affero General Public License as published   ** by the Free Software Foundation, either version 3 or (at your option)   ** any later version. This program is distributed without any warranty.    ** See the file COPYING.agpl-v3 for details.                               *\*************************************************************************//* Listing 46-9 */#include "svmsg_file.h"static int clientId;static voidremoveQueue(void){    if (msgctl(clientId, IPC_RMID, NULL) == -1)        errExit("msgctl");}static void terminate(Boolean useExit3){    char *s;    /* Dump core if EF_DUMPCORE environment variable is defined and       is a nonempty string; otherwise call exit(3) or _exit(2),       depending on the value of 'useExit3'. */    s = getenv("EF_DUMPCORE");    if (s != NULL && *s != '\0')        abort();    else if (useExit3)        exit(EXIT_FAILURE);    else        _exit(EXIT_FAILURE);}static void outputError(Boolean useErr, int err, Boolean flushStdout,const char *format, va_list ap){#define BUF_SIZE 500#define MAX_ENAME 50    char buf[BUF_SIZE], userMsg[BUF_SIZE], errText[BUF_SIZE],ename[BUF_SIZE];    vsnprintf(userMsg, BUF_SIZE, format, ap);    if (useErr)        snprintf(errText, BUF_SIZE, " [%s %s]",                (err > 0 && err <= MAX_ENAME) ?                ename[err] : "?UNKNOWN?", strerror(err));    else        snprintf(errText, BUF_SIZE, ":");    snprintf(buf, BUF_SIZE, "ERROR%s %s\n", errText, userMsg);    if (flushStdout)        fflush(stdout);       /* Flush any pending stdout */    fputs(buf, stderr);    fflush(stderr);           /* In case stderr is not line-buffered */}void errMsg(const char *format, ...){    va_list argList;    int savedErrno;    savedErrno = errno;       /* In case we change it here */    va_start(argList, format);    outputError(TRUE, errno, TRUE, format, argList);    va_end(argList);    errno = savedErrno;}void usageErr(const char *format, ...){    va_list argList;    fflush(stdout);           /* Flush any pending stdout */    fprintf(stderr, "Usage: ");    va_start(argList, format);    vfprintf(stderr, format, argList);    va_end(argList);    fflush(stderr);           /* In case stderr is not line-buffered */    exit(EXIT_FAILURE);}void cmdLineErr(const char *format, ...){    va_list argList;    fflush(stdout);           /* Flush any pending stdout */    fprintf(stderr, "Command-line usage error: ");    va_start(argList, format);    vfprintf(stderr, format, argList);    va_end(argList);    fflush(stderr);           /* In case stderr is not line-buffered */    exit(EXIT_FAILURE);}void errExit(const char *format, ...){    va_list argList;    va_start(argList, format);    outputError(TRUE, errno, TRUE, format, argList);    va_end(argList);    terminate(TRUE);}int cli(int argc, char *argv[]){    struct requestMsg req;    struct responseMsg resp;    int serverId, numMsgs;    ssize_t msgLen, totBytes;    if (argc != 2 || strcmp(argv[1], "--help") == 0)        usageErr("%s pathname\n", argv[0]);    if (strlen(argv[1]) > sizeof(req.pathname) - 1)        cmdLineErr("pathname too long (max: %ld bytes)\n",                (long) sizeof(req.pathname) - 1);    /* Get server's queue identifier; create queue for response */    serverId = msgget(SERVER_KEY, S_IWUSR);    if (serverId == -1)        errExit("msgget - server message queue");    clientId = msgget(IPC_PRIVATE, S_IRUSR | S_IWUSR | S_IWGRP);    if (clientId == -1)        errExit("msgget - client message queue");    if (atexit(removeQueue) != 0)        errExit("atexit");    /* Send message asking for file named in argv[1] */    req.mtype = 1;                      /* Any type will do */    req.clientId = clientId;    strncpy(req.pathname, argv[1], sizeof(req.pathname) - 1);    req.pathname[sizeof(req.pathname) - 1] = '\0';                                        /* Ensure string is terminated */    if (msgsnd(serverId, &req, REQ_MSG_SIZE, 0) == -1)        errExit("msgsnd");    /* Get first response, which may be failure notification */    msgLen = msgrcv(clientId, &resp, RESP_MSG_SIZE, 0, 0);    if (msgLen == -1)        errExit("msgrcv");    if (resp.mtype == RESP_MT_FAILURE) {        printf("%s\n", resp.data);      /* Display msg from server */        if (msgctl(clientId, IPC_RMID, NULL) == -1)            errExit("msgctl");        exit(EXIT_FAILURE);    }    /* File was opened successfully by server; process messages       (including the one already received) containing file data */    totBytes = msgLen;                  /* Count first message */    for (numMsgs = 1; resp.mtype == RESP_MT_DATA; numMsgs++) {        msgLen = msgrcv(clientId, &resp, RESP_MSG_SIZE, 0, 0);        if (msgLen == -1)            errExit("msgrcv");        printf("%s",resp.data);        totBytes += msgLen;    }    printf("Received %ld bytes (%d messages)\n", (long) totBytes, numMsgs);    exit(EXIT_SUCCESS);}

/*************************************************************************\*                  Copyright (C) Michael Kerrisk, 2010.                   **                                                                         ** This program is free software. You may use, modify, and redistribute it ** under the terms of the GNU Affero General Public License as published   ** by the Free Software Foundation, either version 3 or (at your option)   ** any later version. This program is distributed without any warranty.    ** See the file COPYING.agpl-v3 for details.                               *\*************************************************************************//* Listing 46-8 */#include "svmsg_file.h"//extern  void outputError(Boolean useErr, int err, Boolean flushStdout,const char *format, va_list ap);static void  grimReaper(int sig)             /* SIGCHLD handler */{    int savedErrno;    savedErrno = errno;                 /* waitpid() might change 'errno' */    while (waitpid(-1, NULL, WNOHANG) > 0)        continue;    errno = savedErrno;}static void serveRequest(const struct requestMsg *req)  /* Executed in child process: serve a single client */{    int fd;    ssize_t numRead;    struct responseMsg resp;    fd = open(req->pathname, O_RDONLY);    if (fd == -1) {                     /* Open failed: send error text */        resp.mtype = RESP_MT_FAILURE;        snprintf(resp.data, sizeof(resp.data), "%s", "Couldn't open");        msgsnd(req->clientId, &resp, strlen(resp.data) + 1, 0);        exit(EXIT_FAILURE);             /* and terminate */    }    /* Transmit file contents in messages with type RESP_MT_DATA. We don't       diagnose read() and msgsnd() errors since we can't notify client. */    resp.mtype = RESP_MT_DATA;    while ((numRead = read(fd, resp.data, RESP_MSG_SIZE)) > 0)        if (msgsnd(req->clientId, &resp, numRead, 0) == -1)            break;    /* Send a message of type RESP_MT_END to signify end-of-file */    resp.mtype = RESP_MT_END;    msgsnd(req->clientId, &resp, 0, 0);         /* Zero-length mtext */}int main(int argc, char *argv[]){    struct requestMsg req;    pid_t pid;    ssize_t msgLen;    int serverId;    struct sigaction sa;    /* Create server message queue */    serverId = msgget(SERVER_KEY, IPC_CREAT | IPC_EXCL |                            S_IRUSR | S_IWUSR | S_IWGRP);    if (serverId == -1)        errExit("msgget");    /* Establish SIGCHLD handler to reap terminated children */    sigemptyset(&sa.sa_mask);    sa.sa_flags = SA_RESTART;    sa.sa_handler = grimReaper;    if (sigaction(SIGCHLD, &sa, NULL) == -1)        errExit("sigaction");    /* Read requests, handle each in a separate child process */    for (;;) {        msgLen = msgrcv(serverId, &req, REQ_MSG_SIZE, 0, 0);        if (msgLen == -1) {            if (errno == EINTR)         /* Interrupted by SIGCHLD handler? */                continue;               /* ... then restart msgrcv() */            errMsg("msgrcv");           /* Some other error */            break;                      /* ... so terminate loop */        }        pid = fork();                   /* Create child process */        if (pid == -1) {            errMsg("fork");            break;        }        if (pid == 0) {                 /* Child handles request */            serveRequest(&req);            _exit(EXIT_SUCCESS);        }printf("--------------------------------------------------------\n");        /* Parent loops to receive next client request */    }    /* If msgrcv() or fork() fails, remove server MQ and exit */    if (msgctl(serverId, IPC_RMID, NULL) == -1)        errExit("msgctl");    exit(EXIT_SUCCESS);}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.