上面是在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 8192
struct 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 void
removeQueue(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);
}