unix网络编程各种TCP客户-服务器程序设计实例(三)

第五种  TCP预先派生子进程服务器程序:

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

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

child.h:

  1. typedef struct {  
  2.   pid_t     child_pid;      /* process ID */  
  3.   int       child_pipefd;   /* parent's stream pipe to/from child */  
  4.   int       child_status;   /* 0 = ready */  
  5.   long      child_count;    /* # connections handled */  
  6. } Child;  
  7.   
  8. Child   *cptr;      /* array of Child structures; calloc'ed */  

Child.c:

  1. /* include child_make */  
  2. #include    "unp.h"  
  3. #include    "child.h"  
  4.   
  5. Child   *cptr;      /* array of Child structures; calloc'ed */  
  6. pid_t  
  7. child_make(int i, int listenfd, int addrlen)  
  8. {  
  9.     int     sockfd[2];  
  10.     pid_t   pid;  
  11.     void    child_main(int, int, int);  
  12.   
  13.     Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);  
  14.   
  15.     if ( (pid = Fork()) > 0) {  
  16.         Close(sockfd[1]);  
  17.         cptr[i].child_pid = pid;  
  18.         cptr[i].child_pipefd = sockfd[0];  
  19.         cptr[i].child_status = 0;  
  20.         return(pid);        /* parent */  
  21.     }  
  22.   
  23.     Dup2(sockfd[1], STDERR_FILENO);     /* child's stream pipe to parent */  
  24.     Close(sockfd[0]);  
  25.     Close(sockfd[1]);  
  26.     Close(listenfd);                    /* child does not need this open */  
  27.     child_main(i, listenfd, addrlen);   /* never returns */  
  28. }  
  29. /* end child_make */  
  30.   
  31. /* include child_main */  
  32. void  
  33. child_main(int i, int listenfd, int addrlen)  
  34. {  
  35.     char            c;  
  36.     int             connfd;  
  37.     ssize_t         n;  
  38.     void            web_child(int);  
  39.   
  40.     printf("child %ld starting\n", (long) getpid());  
  41.     for ( ; ; ) {  
  42.         if ( (n = Read_fd(STDERR_FILENO, &c, 1, &connfd)) == 0)  
  43.             err_quit("read_fd returned 0");  
  44.         if (connfd < 0)  
  45.             err_quit("no descriptor from read_fd");  
  46.   
  47.         web_child(connfd);              /* process request */  
  48.         Close(connfd);  
  49.   
  50.         Write(STDERR_FILENO, "", 1);    /* tell parent we're ready again */  
  51.     }  
  52. }  
  53. /* end child_main */  

pr_cpu_time.c:

  1. #include    "unp.h"  
  2. #include    <sys/resource.h>  
  3.   
  4. #ifndef HAVE_GETRUSAGE_PROTO  
  5. int     getrusage(int, struct rusage *);  
  6. #endif  
  7.   
  8. void  
  9. pr_cpu_time(void)  
  10. {  
  11.     double          user, sys;  
  12.     struct rusage   myusage, childusage;  
  13.   
  14.     if (getrusage(RUSAGE_SELF, &myusage) < 0)  
  15.         err_sys("getrusage error");  
  16.     if (getrusage(RUSAGE_CHILDREN, &childusage) < 0)  
  17.         err_sys("getrusage error");  
  18.   
  19.     user = (double) myusage.ru_utime.tv_sec +  
  20.                     myusage.ru_utime.tv_usec/1000000.0;  
  21.     user += (double) childusage.ru_utime.tv_sec +  
  22.                      childusage.ru_utime.tv_usec/1000000.0;  
  23.     sys = (double) myusage.ru_stime.tv_sec +  
  24.                    myusage.ru_stime.tv_usec/1000000.0;  
  25.     sys += (double) childusage.ru_stime.tv_sec +  
  26.                     childusage.ru_stime.tv_usec/1000000.0;  
  27.   
  28.     printf("\nuser time = %g, sys time = %g\n", user, sys);  
  29. }  

web_child.c:

  1. #include    "unp.h"  
  2.   
  3. #define MAXN    16384       /* max # bytes client can request */  
  4.   
  5. void  
  6. web_child(int sockfd)  
  7. {  
  8.     int         ntowrite;  
  9.     ssize_t     nread;  
  10.     char        line[MAXLINE], result[MAXN];  
  11.   
  12.     for ( ; ; ) {  
  13.         if ( (nread = Readline(sockfd, line, MAXLINE)) == 0)  
  14.             return;     /* connection closed by other end */  
  15.   
  16.             /* 4line from client specifies #bytes to write back */  
  17.         ntowrite = atol(line);  
  18.         if ((ntowrite <= 0) || (ntowrite > MAXN))  
  19.             err_quit("client request for %d bytes", ntowrite);  
  20.   
  21.         Writen(sockfd, result, ntowrite);  
  22.     }  
  23. }  


 

client.c:

  1. #include    "unp.h"  
  2.   
  3. #define MAXN    16384       /* max # bytes to request from server */  
  4.   
  5. int  
  6. main(int argc, char **argv)  
  7. {  
  8.     int     i, j, fd, nchildren, nloops, nbytes;  
  9.     pid_t   pid;  
  10.     ssize_t n;  
  11.     char    request[MAXLINE], reply[MAXN];  
  12.   
  13.     if (argc != 6)  
  14.         err_quit("usage: client <hostname or IPaddr> <port> <#children> "  
  15.                  "<#loops/child> <#bytes/request>");  
  16.   
  17.     nchildren = atoi(argv[3]);  
  18.     nloops = atoi(argv[4]);  
  19.     nbytes = atoi(argv[5]);  
  20.     snprintf(request, sizeof(request), "%d\n", nbytes); /* newline at end */  
  21.   
  22.     for (i = 0; i < nchildren; i++) {  
  23.         if ( (pid = Fork()) == 0) {     /* child */  
  24.             for (j = 0; j < nloops; j++) {  
  25.                 fd = Tcp_connect(argv[1], argv[2]);  
  26.   
  27.                 Write(fd, request, strlen(request));  
  28.   
  29.                 if ( (n = Readn(fd, reply, nbytes)) != nbytes)  
  30.                     err_quit("server returned %d bytes", n);  
  31.   
  32.                 Close(fd);      /* TIME_WAIT on client, not server */  
  33.             }  
  34.             printf("child %d done\n", i);  
  35.             exit(0);  
  36.         }  
  37.         /* parent loops around to fork() again */  
  38.     }  
  39.   
  40.     while (wait(NULL) > 0)   /* now parent waits for all children */  
  41.         ;  
  42.     if (errno != ECHILD)  
  43.         err_sys("wait error");  
  44.   
  45.     exit(0);  
  46. }  

server.c:

  1. /* include serv05a */  
  2. #include    "unp.h"  
  3. #include    "child.h"  
  4.   
  5. static int      nchildren;  
  6.   
  7. int  
  8. main(int argc, char **argv)  
  9. {  
  10.     int         listenfd, i, navail, maxfd, nsel, connfd, rc;  
  11.     void        sig_int(int);  
  12.     pid_t       child_make(int, int, int);  
  13.     ssize_t     n;  
  14.     fd_set      rset, masterset;  
  15.     socklen_t   addrlen, clilen;  
  16.     struct sockaddr *cliaddr;  
  17.   
  18.     if (argc == 3)  
  19.         listenfd = Tcp_listen(NULL, argv[1], &addrlen);  
  20.     else if (argc == 4)  
  21.         listenfd = Tcp_listen(argv[1], argv[2], &addrlen);  
  22.     else  
  23.         err_quit("usage: serv05 [ <host> ] <port#> <#children>");  
  24.   
  25.     FD_ZERO(&masterset);  
  26.     FD_SET(listenfd, &masterset);  
  27.     maxfd = listenfd;  
  28.     cliaddr = Malloc(addrlen);  
  29.   
  30.     nchildren = atoi(argv[argc-1]);  
  31.     navail = nchildren;  
  32.     cptr = Calloc(nchildren, sizeof(Child));  
  33.   
  34.         /* 4prefork all the children */  
  35.     for (i = 0; i < nchildren; i++) {  
  36.         child_make(i, listenfd, addrlen);   /* parent returns */  
  37.         FD_SET(cptr[i].child_pipefd, &masterset);  
  38.         maxfd = max(maxfd, cptr[i].child_pipefd);  
  39.     }  
  40.   
  41.     Signal(SIGINT, sig_int);  
  42.   
  43.     for ( ; ; ) {  
  44.         rset = masterset;  
  45.         if (navail <= 0)  
  46.             FD_CLR(listenfd, &rset);    /* turn off if no available children */  
  47.         nsel = Select(maxfd + 1, &rset, NULL, NULL, NULL);  
  48.   
  49.             /* 4check for new connections */  
  50.         if (FD_ISSET(listenfd, &rset)) {  
  51.             clilen = addrlen;  
  52.             connfd = Accept(listenfd, cliaddr, &clilen);  
  53.   
  54.             for (i = 0; i < nchildren; i++)  
  55.                 if (cptr[i].child_status == 0)  
  56.                     break;              /* available */  
  57.   
  58.             if (i == nchildren)  
  59.                 err_quit("no available children");  
  60.             cptr[i].child_status = 1;   /* mark child as busy */  
  61.             cptr[i].child_count++;  
  62.             navail--;  
  63.   
  64.             n = Write_fd(cptr[i].child_pipefd, "", 1, connfd);  
  65.             Close(connfd);  
  66.             if (--nsel == 0)  
  67.                 continue;   /* all done with select() results */  
  68.         }  
  69.   
  70.             /* 4find any newly-available children */  
  71.         for (i = 0; i < nchildren; i++) {  
  72.             if (FD_ISSET(cptr[i].child_pipefd, &rset)) {  
  73.                 if ( (n = Read(cptr[i].child_pipefd, &rc, 1)) == 0)  
  74.                     err_quit("child %d terminated unexpectedly", i);  
  75.                 cptr[i].child_status = 0;  
  76.                 navail++;  
  77.                 if (--nsel == 0)  
  78.                     break;  /* all done with select() results */  
  79.             }  
  80.         }  
  81.     }  
  82. }  
  83. /* end serv05a */  
  84.   
  85. void  
  86. sig_int(int signo)  
  87. {  
  88.     int     i;  
  89.     void    pr_cpu_time(void);  
  90.   
  91.         /* 4terminate all children */  
  92.     for (i = 0; i < nchildren; i++)  
  93.         kill(cptr[i].child_pid, SIGTERM);  
  94.     while (wait(NULL) > 0)       /* wait for all children */  
  95.         ;  
  96.     if (errno != ECHILD)  
  97.         err_sys("wait error");  
  98.   
  99.     pr_cpu_time();  
  100.   
  101.     for (i = 0; i < nchildren; i++)  
  102.         printf("child %d, %ld connections\n", i, cptr[i].child_count);  
  103.   
  104.     exit(0);  
  105. }  

编译命令:

gcc server.c child.c pr_cpu_time.c web_child.c -o server -lunp

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值