APUE2e之Exercise 16.3 Solution A

17 篇文章 0 订阅
11 篇文章 0 订阅

Below is the code for the server side. 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-3A.c
 *
 * Description: single thread, multiple endpoint to provide "ruptime" service
 *
 * Created On: Jan 11, 2012 
 *
 * @author: Huang Zhu
 *
 * @email: zhuhuang.zp@gmail.com
 */
 
 
#include <apueerr.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);
}
 
 
void daemonize(const char *cmd)
{
	int					i, fd0, fd1, fd2;
	pid_t				pid;
	struct rlimit		rl;
	struct sigaction	sa;
 
	/*
	 * 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(fd_set *set, int maxfd, Server_FD *fdarray, int maxindex)
{
	int clientfd;
	int serverfd;
	int ready;
	FILE *fp;
	char buf[BUFLEN];
	int i;
 
	for(;;){
		//A socket with pending connect requests will appear to be readable. Use only read sets for select.
		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)){
					clientfd = accept(serverfd, NULL, NULL); //we don't care about client's identity
					if(clientfd < 0){
						syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno));
						exit(1);
					}
 
					//popen, pclose: apue2e, page 503
					if((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);
						pclose(fp);
					}
					close(clientfd);
				}
			}
		}
	}
}
 
 
int main(int argc, char *argv[])
{
	struct addrinfo *ailist, *aip;
	struct addrinfo hint;
	int sockfd, err, n;
	char *host;
	fd_set sockset; //read sets
	int maxfd = -1; //maximum socket descriptor
	Server_FD fdarray[FD_SETSIZE]; //array to store server sockets waiting for connection requests
	int maxindex = 0; //the index past the last effective element in array fdarray
 
	if(argc != 1)
		err_quit("usage: ruptimed");
#ifdef _SC_HOST_NAME_MAX
	n = sysconf(_SC_HOST_NAME_MAX);
	if(n < 0)
#endif
		n = 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 sockset
			FD_SET(sockfd, &sockset);
 
			//add the socket and corresponding address to array fdarray
			fdarray[maxindex].fd = sockfd;
			fdarray[maxindex].addr = *aip;
			maxindex++;
		}
	}
 
	if(maxfd >=0)
		serve(&sockset, maxfd, fdarray, maxindex);
 
	exit(1);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值