第五种 TCP预先派生子进程服务器程序:
对预先派生子进程服务器的最后一种改动就是由父进程调用accept,然后再将所接受的已连接描述字传递给子进程。父进程必须跟踪子进程的忙闲状态,以便给空闲子进程传递新的描述字。为每个子进程维护一个信息结构,用来管理各子进程。

在调用fork之前,先创建一个字节流管道(Unix域的字节流套接口),它是Unix域的字节流套接口。当子进程派生后,父进程关闭一个描述字(sockfd[1]),子进程关闭另一个描述字(sockfd[0]),此外,子进程将流管道的字节所在端(sockfd[1])复制到标准输出。

child.h:
-
typedef struct {
-
pid_t child_pid; /* process ID */
-
int child_pipefd; /* parent‘s stream pipe to/from child */
-
int child_status; /* 0 = ready */
-
long child_count; /* # connections handled */
-
} Child;
-
-
Child *cptr; /* array of Child structures; calloc‘ed */
Child.c:
-
/* include child_make */
-
#include "unp.h"
-
#include "child.h"
-
-
Child *cptr; /* array of Child structures; calloc‘ed */
-
pid_t
-
child_make(int i, int listenfd, int addrlen)
-
{
-
int sockfd[2];
-
pid_t pid;
-
void child_main(int, int, int);
-
-
Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
-
-
if ( (pid = Fork()) > 0) {
-
Close(sockfd[1]);
-
cptr[i].child_pid = pid;
-
cptr[i].child_pipefd = sockfd[0];
-
cptr[i].child_status = 0;
-
return(pid); /* parent */
-
}
-
-
Dup2(sockfd[1], STDERR_FILENO); /* child‘s stream pipe to parent */
-
Close(sockfd[0]);
-
Close(sockfd[1]);
-
Close(listenfd); /* child does not need this open */
-
child_main(i, listenfd, addrlen); /* never returns */
-
}
-
/* end child_make */
-
-
/* include child_main */
-
void
-
child_main(int i, int listenfd, int addrlen)
-
{
-
char c;
-
int connfd;
-
ssize_t n;
-
void web_child(int);
-
-
printf("child %ld starting\n", (long) getpid());
-
for ( ; ; ) {
-
if ( (n = Read_fd(STDERR_FILENO, &c, 1, &connfd)) == 0)
-
err_quit("read_fd returned 0");
-
if (connfd < 0)
-
err_quit("no descriptor from read_fd");
-
-
web_child(connfd); /* process request */
-
Close(connfd);
-
-
Write(STDERR_FILENO, "", 1); /* tell parent we‘re ready again */
-
}
-
}
-
/* end child_main */
pr_cpu_time.c:
-
#include "unp.h"
-
#include <sys/resource.h>
-
-
#ifndef HAVE_GETRUSAGE_PROTO
-
int getrusage(int, struct rusage *);
-
#endif
-
-
void
-
pr_cpu_time(void)
-
{
-
double user, sys;
-
struct rusage myusage, childusage;
-
-
if (getrusage(RUSAGE_SELF, &myusage) < 0)
-
err_sys("getrusage error");
-
if (getrusage(RUSAGE_CHILDREN, &childusage) < 0)
-
err_sys("getrusage error");
-
-
user = (double) myusage.ru_utime.tv_sec +
-
myusage.ru_utime.tv_usec/1000000.0;
-
user += (double) childusage.ru_utime.tv_sec +
-
childusage.ru_utime.tv_usec/1000000.0;
-
sys = (double) myusage.ru_stime.tv_sec +
-
myusage.ru_stime.tv_usec/1000000.0;
-
sys += (double) childusage.ru_stime.tv_sec +
-
childusage.ru_stime.tv_usec/1000000.0;
-
-
printf("\nuser time = %g, sys time = %g\n", user, sys);
-
}
web_child.c:
-
#include "unp.h"
-
-
#define MAXN 16384 /* max # bytes client can request */
-
-
void
-
web_child(int sockfd)
-
{
-
int ntowrite;
-
ssize_t nread;
-
char line[MAXLINE], result[MAXN];
-
-
for ( ; ; ) {
-
if ( (nread = Readline(sockfd, line, MAXLINE)) == 0)
-
return; /* connection closed by other end */
-
-
/* 4line from client specifies #bytes to write back */
-
ntowrite = atol(line);
-
if ((ntowrite <= 0) || (ntowrite > MAXN))
-
err_quit("client request for %d bytes", ntowrite);
-
-
Writen(sockfd, result, ntowrite);
-
}
-
}
client.c:
-
#include "unp.h"
-
-
#define MAXN 16384 /* max # bytes to request from server */
-
-
int
-
main(int argc, char **argv)
-
{
-
int i, j, fd, nchildren, nloops, nbytes;
-
pid_t pid;
-
ssize_t n;
-
char request[MAXLINE], reply[MAXN];
-
-
if (argc != 6)
-
err_quit("usage: client <hostname or IPaddr> <port> <#children> "
-
"<#loops/child> <#bytes/request>");
-
-
nchildren = atoi(argv[3]);
-
nloops = atoi(argv[4]);
-
nbytes = atoi(argv[5]);
-
snprintf(request, sizeof(request), "%d\n", nbytes); /* newline at end */
-
-
for (i = 0; i < nchildren; i++) {
-
if ( (pid = Fork()) == 0) { /* child */
-
for (j = 0; j < nloops; j++) {
-
fd = Tcp_connect(argv[1], argv[2]);
-
-
Write(fd, request, strlen(request));
-
-
if ( (n = Readn(fd, reply, nbytes)) != nbytes)
-
err_quit("server returned %d bytes", n);
-
-
Close(fd); /* TIME_WAIT on client, not server */
-
}
-
printf("child %d done\n", i);
-
exit(0);
-
}
-
/* parent loops around to fork() again */
-
}
-
-
while (wait(NULL) > 0) /* now parent waits for all children */
-
;
-
if (errno != ECHILD)
-
err_sys("wait error");
-
-
exit(0);
-
}
server.c:
-
/* include serv05a */
-
#include "unp.h"
-
#include "child.h"
-
-
static int nchildren;
-
-
int
-
main(int argc, char **argv)
-
{
-
int listenfd, i, navail, maxfd, nsel, connfd, rc;
-
void sig_int(int);
-
pid_t child_make(int, int, int);
-
ssize_t n;
-
fd_set rset, masterset;
-
socklen_t addrlen, clilen;
-
struct sockaddr *cliaddr;
-
-
if (argc == 3)
-
listenfd = Tcp_listen(NULL, argv[1], &addrlen);
-
else if (argc == 4)
-
listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
-
else
-
err_quit("usage: serv05 [ <host> ] <port#> <#children>");
-
-
FD_ZERO(&masterset);
-
FD_SET(listenfd, &masterset);
-
maxfd = listenfd;
-
cliaddr = Malloc(addrlen);
-
-
nchildren = atoi(argv[argc-1]);
-
navail = nchildren;
-
cptr = Calloc(nchildren, sizeof(Child));
-
-
/* 4prefork all the children */
-
for (i = 0; i < nchildren; i++) {
-
child_make(i, listenfd, addrlen); /* parent returns */
-
FD_SET(cptr[i].child_pipefd, &masterset);
-
maxfd = max(maxfd, cptr[i].child_pipefd);
-
}
-
-
Signal(SIGINT, sig_int);
-
-
for ( ; ; ) {
-
rset = masterset;
-
if (navail <= 0)
-
FD_CLR(listenfd, &rset); /* turn off if no available children */
-
nsel = Select(maxfd + 1, &rset, NULL, NULL, NULL);
-
-
/* 4check for new connections */
-
if (FD_ISSET(listenfd, &rset)) {
-
clilen = addrlen;
-
connfd = Accept(listenfd, cliaddr, &clilen);
-
-
for (i = 0; i < nchildren; i++)
-
if (cptr[i].child_status == 0)
-
break; /* available */
-
-
if (i == nchildren)
-
err_quit("no available children");
-
cptr[i].child_status = 1; /* mark child as busy */
-
cptr[i].child_count++;
-
navail--;
-
-
n = Write_fd(cptr[i].child_pipefd, "", 1, connfd);
-
Close(connfd);
-
if (--nsel == 0)
-
continue; /* all done with select() results */
-
}
-
-
/* 4find any newly-available children */
-
for (i = 0; i < nchildren; i++) {
-
if (FD_ISSET(cptr[i].child_pipefd, &rset)) {
-
if ( (n = Read(cptr[i].child_pipefd, &rc, 1)) == 0)
-
err_quit("child %d terminated unexpectedly", i);
-
cptr[i].child_status = 0;
-
navail++;
-
if (--nsel == 0)
-
break; /* all done with select() results */
-
}
-
}
-
}
-
}
-
/* end serv05a */
-
-
void
-
sig_int(int signo)
-
{
-
int i;
-
void pr_cpu_time(void);
-
-
/* 4terminate all children */
-
for (i = 0; i < nchildren; i++)
-
kill(cptr[i].child_pid, SIGTERM);
-
while (wait(NULL) > 0) /* wait for all children */
-
;
-
if (errno != ECHILD)
-
err_sys("wait error");
-
-
pr_cpu_time();
-
-
for (i = 0; i < nchildren; i++)
-
printf("child %d, %ld connections\n", i, cptr[i].child_count);
-
-
exit(0);
-
}
编译命令:
gcc server.c child.c pr_cpu_time.c web_child.c -o server -lunp
版权声明:本文为博主http://www.zuiniusn.com 原创文章,未经博主允许不得转载。
unix网络编程各种TCP客户-服务器程序设计实例(三)
原文:http://blog.csdn.net/u013141940/article/details/46848477