上面是在eclipse下面的工程的編譯情況,這個代碼是來自《PRAISE FOR THE LINUX PROGRAMMING INTERFACE》一書。有三個檔案組成。
/*************************************************************************\* 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);}