UNIX网络编程——客户/服务器程序设计示范(二)

来源:互联网 发布:jsp windows.onload 编辑:程序博客网 时间:2024/05/14 04:32

    TCP并发服务器程序,每个客户一个子进程

      

             

         传统上并发服务器调用fork派生一个子进程来处理每个客户。这使得服务器能够同时为多个客户服务,每个进程一个客户。客户数目的唯一限制是操作系统对以其名义运行服务器的用户ID能够同时有多个子进程的限制。并发服务器的问题在于为每个客户现场fork一个子进程比较耗费CPU时间。

         

        本函数为每个客户连接fork一个子进程并处理来自垂死的子进程的SIGCHLD信号。我们还捕获由键入终端中断按键产生的SIGINT信号。在客户运行完毕之后我们键入该键以显示服务器程序运行所需的CPU时间。下面给出了SIGINT信号处理函数。这是一个信号处理函数不返回而直接终止进程。
       getrusage函数被调用了两次,分别返回调用进程(RUSAGE_SELF)和它的所有已终止子进程(RUSAGE_CHILDREN)的资源利用统计。所显示的值包括总的系统时间(内核在代表调用进程执行系统调用上耗费的CPU时间)。
        客户在建立与服务器的连接之后通过该连接写出一行文本,指出需由服务器发送多少字节的数据给客户。这一点与HTTP有些类似:客户发送一个小请求,服务器响应以所期望的信息(例如一个HTML文件或一副GIF图片),在HTTP应用系统中,服务器通常在发送回所请求的数据之间就关闭连接,不过较新的版本允许使用持续连接,为在某个时限以内到达的额外客户请求继续保持TCP连接开发一段时间。
        在web_child函数中,服务器允许来自客户的额外请求。

#include"unp.h"void pr_cpu_time(void){doubleuser, sys;struct rusagemyusage, 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);}void sig_int(int signo){voidpr_cpu_time(void);pr_cpu_time();exit(0);}void sig_chld(int signo){pid_tpid;intstat;while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)printf("child %d terminated\n", pid);return;}#defineMAXN16384/* max # bytes client can request */void web_child(int sockfd){intntowrite;ssize_tnread;charline[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);}}int main(int argc, char **argv){intlistenfd, connfd;pid_tchildpid;voidsig_chld(int), sig_int(int), web_child(int);socklen_tclilen, addrlen;struct sockaddr*cliaddr;if (argc == 2)listenfd = Tcp_listen(NULL, argv[1], &addrlen);else if (argc == 3)listenfd = Tcp_listen(argv[1], argv[2], &addrlen);elseerr_quit("usage: serv01 [ <host> ] <port#>");cliaddr = Malloc(addrlen);Signal(SIGCHLD, sig_chld);Signal(SIGINT, sig_int);for ( ; ; ) {clilen = addrlen;if ( (connfd = accept(listenfd, cliaddr, &clilen)) < 0) {if (errno == EINTR)continue;/* back to for() */elseerr_sys("accept error");}if ( (childpid = Fork()) == 0) {/* child process */Close(listenfd);/* close listening socket */web_child(connfd);/* process request */exit(0);}Close(connfd);/* parent closes connected socket */}}


原创粉丝点击