APUE2e之Exercise 16.3 Solution B

来源:互联网 发布:知天下图吧 编辑:程序博客网 时间:2024/06/10 01:28

Code for client side is in Figure 16.14 in APUE2e, Page 568.

To compile the program, check this post: posix thread相关函数的编译(undefined reference to `pthread_create’)


/**    * apue-chap16: exercise16-3B.c * * Description: multiple threads, multiple endpoint to provide "ruptime" service * * Created On: Jan 11, 2012  * * @author: Huang Zhu * * @email: zhuhuang.zp@gmail.com */  #include <apueerr.h>#include <pthread.h>#include <netdb.h>#include <errno.h>#include <fcntl.h>#include <stdlib.h>#include <syslog.h>#include <sys/socket.h>#include <sys/resource.h>#include <sys/select.h>  #define BUFLEN 128#define QLEN 10 #ifndef HOST_NAME_MAX#define HOST_NAME_MAX 256#endif typedef struct Server_FD{    int fd;    struct addrinfo addr;} Server_FD; int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen){int sockfd, err;int reuse = 1; if((sockfd = socket(addr->sa_family, type, 0)) < 0)return(-1); if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0){err = errno;goto errout;}if(bind(sockfd, addr, alen) < 0){err = errno;goto errout;}if(type == SOCK_STREAM || type == SOCK_SEQPACKET){if(listen(sockfd, qlen) < 0){err = errno;goto errout;}}return(sockfd); errout:close(sockfd);errno = err;return(-1);} voiddaemonize(const char *cmd){inti, fd0, fd1, fd2;pid_tpid;struct rlimitrl;struct sigactionsa; /* * Clear file creation mask. */umask(0); /* * Get maximum number of file descriptors. */if (getrlimit(RLIMIT_NOFILE, &rl) < 0)err_quit("%s: can't get file limit", cmd); /* * Become a session leader to lose controlling TTY. */if ((pid = fork()) < 0)err_quit("%s: can't fork", cmd);else if (pid != 0) /* parent */exit(0);setsid(); /* * Ensure future opens won't allocate controlling TTYs. */sa.sa_handler = SIG_IGN;sigemptyset(&sa.sa_mask);sa.sa_flags = 0;if (sigaction(SIGHUP, &sa, NULL) < 0)err_quit("%s: can't ignore SIGHUP");if ((pid = fork()) < 0)err_quit("%s: can't fork", cmd);else if (pid != 0) /* parent */exit(0); /* * Change the current working directory to the root so * we won't prevent file systems from being unmounted. */if (chdir("/") < 0)err_quit("%s: can't change directory to /"); /* * Close all open file descriptors. */if (rl.rlim_max == RLIM_INFINITY)rl.rlim_max = 1024;for (i = 0; i < rl.rlim_max; i++)close(i); /* * Attach file descriptors 0, 1, and 2 to /dev/null. */fd0 = open("/dev/null", O_RDWR);fd1 = dup(0);fd2 = dup(0); /* * Initialize the log file. */openlog(cmd, LOG_CONS, LOG_DAEMON);if (fd0 != 0 || fd1 != 1 || fd2 != 2) {syslog(LOG_ERR, "unexpected file descriptors %d %d %d",  fd0, fd1, fd2);exit(1);}} void* serve_client(void* fd){int clientfd;int sockfd;FILE *fp;char buf[BUFLEN];pthread_t tid; tid = pthread_self(); sockfd = (int)fd;clientfd = accept(sockfd, NULL, NULL); //we don't care about client's identityif(clientfd < 0){syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno));exit(1);} //popen, pclose: apue2e, page 503if((fp = popen("/usr/bin/uptime", "r")) == NULL){sprintf(buf, "error: %s\n", strerror(errno));send(clientfd, buf, strlen(buf), 0);}else{while(fgets(buf, BUFLEN, fp) != NULL)send(clientfd, buf, strlen(buf), 0); //prove that the thread workssprintf(buf, " thread id: %ld\n", tid);send(clientfd, buf, strlen(buf), 0); pclose(fp);}close(clientfd); return((void*)0);} void serve(fd_set *set, int maxfd, Server_FD *fdarray, int maxindex){int serverfd;int ready;int i; pthread_t tid;int err; for(;;){if((ready = select(maxfd+1, set, NULL, NULL, NULL)) > 0){for(i = 0; i < maxindex; i++){serverfd = fdarray[i].fd;if(FD_ISSET(serverfd, set)){err = pthread_create(&tid, NULL, serve_client, (void *)serverfd);if(err != 0){syslog(LOG_ERR, "ruptimed: pthread_create error: %s", strerror(err));}}}}}} int main(int argc, char *argv[]){struct addrinfo *ailist, *aip;struct addrinfo hint;int sockfd, err, n;char *host;fd_set sockset; //read setsint maxfd = -1; //maximum socket descriptorServer_FD fdarray[FD_SETSIZE]; //array to store server sockets waiting for connection requestsint maxindex = 0; //the index past the last effective element in array fdarray if(argc != 1)err_quit("usage: ruptimed");#ifdef _SC_HOST_NAME_MAXn = sysconf(_SC_HOST_NAME_MAX);if(n < 0)#endifn = HOST_NAME_MAX;host = malloc(n);if(host == NULL)err_sys("malloc error");if(gethostname(host, n) < 0)err_sys("gethostname error"); printf("Host Name: %s\n", host); daemonize("ruptimed"); hint.ai_flags = AI_CANONNAME;hint.ai_family = 0;hint.ai_socktype = SOCK_STREAM;hint.ai_protocol = 0;hint.ai_addrlen = 0;hint.ai_canonname = NULL;hint.ai_addr = NULL;hint.ai_next = NULL;if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0){syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s", gai_strerror(err));exit(1);} FD_ZERO(&sockset); for(aip = ailist; aip != NULL; aip = aip->ai_next){if((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN)) >= 0){if(sockfd > maxfd)maxfd = sockfd; //add the socket to fd_set socksetFD_SET(sockfd, &sockset); //add the socket and corresponding address to array fdarrayfdarray[maxindex].fd = sockfd;fdarray[maxindex].addr = *aip;maxindex++;}} if(maxfd >=0)serve(&sockset, maxfd, fdarray, maxindex); exit(1);}


原创粉丝点击