第六种 TCP预先派生子进程服务器程序,每个线程各自accept:
预先派生一个子进程池,每个线程各自调用accept接受连接,不过我们不是让每个线程都阻塞在accept调用上,而是直接使用互斥锁来保证线程间互斥地调用accept。
客户端程序还是和unix网络编程各种TCP客户-服务器程序设计实例(三)中的一样,这里就不讲了,我们着重看服务器的程序:
pthread.h:
typedef struct { pthread_t thread_tid; /* thread ID */ long thread_count; /* # connections handled */ } Thread; Thread *tptr; /* array of Thread structures; calloc'ed */ int listenfd, nthreads; socklen_t addrlen; pthread_mutex_t mlock;
pthread.c
#include "unpthread.h" #include "pthread.h" void thread_make(int i) { void *thread_main(void *); Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void *) i); return; /* main thread returns */ } void * thread_main(void *arg) { int connfd; void web_child(int); socklen_t clilen; struct sockaddr *cliaddr; cliaddr = Malloc(addrlen); printf("thread %d starting\n", (int) arg); for ( ; ; ) { clilen = addrlen; Pthread_mutex_lock(&mlock); connfd = Accept(listenfd, cliaddr, &clilen); Pthread_mutex_unlock(&mlock); tptr[(int) arg].thread_count++; web_child(connfd); /* process request */ Close(connfd); } }
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); } }
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); }
server.c
/* include serv07 */ #include "unpthread.h" #include "pthread.h" pthread_mutex_t mlock = PTHREAD_MUTEX_INITIALIZER; int main(int argc, char **argv) { int i; void sig_int(int), thread_make(int); 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: serv07 [ <host> ] <port#> <#threads>"); nthreads = atoi(argv[argc-1]); tptr = Calloc(nthreads, sizeof(Thread)); for (i = 0; i < nthreads; i++) thread_make(i); /* only main thread returns */ Signal(SIGINT, sig_int); for ( ; ; ) pause(); /* everything done by threads */ } /* end serv07 */ void sig_int(int signo) { int i; void pr_cpu_time(void); pr_cpu_time(); for (i = 0; i < nthreads; i++) printf("thread %d, %ld connections\n", i, tptr[i].thread_count); exit(0); }
编译命令:
gcc server.c pthread.c pr_cpu_time.c web_child.c -o server -lunp -lpthread