APUE读书笔记-17高级进程通信(16)
2020-08-21 本文已影响0人
QuietHeart
服务端
下面,我们将要看到服务进程。
头文件opend.h,版本2
头文件opend.h包含一些标准的头文件以及一些全局变量和函数的声明。
如下所示:
#include "apue.h"
#include <errno.h>
#define CS_OPEN "/home/sar/opend" /* well-known name */
#define CL_OPEN "open" /* client's request for server */
extern int debug; /* nonzero if interactive (not daemon) */
extern char errmsg[]; /* error message string to return to client */
extern int oflag; /* open flag: O_xxx ... */
extern char *pathname; /* of file to open for client */
typedef struct { /* one Client struct per connected client */
int fd; /* fd, or -1 if available */
uid_t uid;
} Client;
extern Client *client; /* ptr to malloc'ed array */
extern int client_size; /* # entries in client[] array */
int cli_args(int, char **);
int client_add(int, uid_t);
void client_del(int);
void loop(void);
void request(char *, int, int, uid_t);
用来操作客户进程数组的函数
因为服务进程处理所有的客户进程请求,它必须维护每个客户连接的状态。这个通过一个opend.h中的Client数组来做到。
下面代码就定义了操作这个数组的三个函数:
#include "opend.h"
#define NALLOC 10 /* # client structs to alloc/realloc for */
static void client_alloc(void) /* alloc more entries in the client[] array */
{
int i;
if (client == NULL)
client = malloc(NALLOC * sizeof(Client));
else
client = realloc(client, (client_size+NALLOC)*sizeof(Client));
if (client == NULL)
err_sys("can't alloc for client array");
/* initialize the new entries */
for (i = client_size; i < client_size + NALLOC; i++)
client[i].fd = -1; /* fd of -1 means entry available */
client_size += NALLOC;
}
/*
* Called by loop() when connection request from a new client arrives.
*/
int client_add(int fd, uid_t uid)
{
int i;
if (client == NULL) /* first time we're called */
client_alloc();
again:
for (i = 0; i < client_size; i++) {
if (client[i].fd == -1) { /* find an available entry */
client[i].fd = fd;
client[i].uid = uid;
return(i); /* return index in client[] array */
}
}
/* client array full, time to realloc for more */
client_alloc();
goto again; /* and search again (will work this time) */
}
/*
* Called by loop() when we're done with a client.
*/
void client_del(int fd)
{
int i;
for (i = 0; i < client_size; i++) {
if (client[i].fd == fd) {
client[i].fd = -1;
return;
}
}
log_quit("can't find client entry for fd %d", fd);
}
client_add第一次被调用时,会调用client_alloc给数组分配10个条目的空间。当这10个条目都被使用完了之后,后面对client_add的调用会导致realloc再次分配额外的空间。通过用这个方式动态分配额外的空间,我们不用在编译之前限制客户进程数组的数目。因为服务进程是一个守护进程,所以以上函数如果出现了错误,我们使用之前定义的log_函数来提示错误信息。
服务进程的main函数,版本2
下面的代码中,main函数定义了全局变量,处理了命令行选项,然后调用函数循环。如果我们使用-d选项启动服务进程,那么服务进程会以交互的方式运行而不是守护进程了。当测试服务进程的时候,这个会被使用。
#include "opend.h"
#include <syslog.h>
int debug, oflag, client_size, log_to_stderr;
char errmsg[MAXLINE];
char *pathname;
Client *client = NULL;
int main(int argc, char *argv[])
{
int c;
log_open("open.serv", LOG_PID, LOG_USER);
opterr = 0; /* don't want getopt() writing to stderr */
while ((c = getopt(argc, argv, "d")) != EOF) {
switch (c) {
case 'd': /* debug */
debug = log_to_stderr = 1;
break;
case '?':
err_quit("unrecognized option: -%c", optopt);
}
}
if (debug == 0)
daemonize("opend");
loop(); /* never returns */
}