第五种 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 原创文章,未经博主允许不得转载。
时间: 2024-07-29 15:58:46