1 /** 2 *initserver.c 3 **/ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <sys/socket.h> 8 #include <netinet/in.h> 9 #include <syslog.h> 10 #include <errno.h> 11 12 int 13 initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen) 14 { 15 int fd; 16 int err = 0; 17 int reuse = 1; 18 19 if((fd = socket(addr->sa_family, type, 0)) < 0) 20 return -1; 21 22 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0) { 23 err = errno; 24 goto errout; 25 } 26 27 if(bind(fd, addr, alen) < 0) { 28 err = errno; 29 goto errout; 30 } 31 32 syslog(LOG_DEBUG, "in initserver port: %d\n",((struct sockaddr_in *)addr)->sin_port); 33 34 if(type == SOCK_STREAM || type == SOCK_SEQPACKET) { 35 if(listen(fd, qlen) < 0) 36 { 37 err= errno; 38 goto errout; 39 } 40 } 41 42 return (fd); 43 44 errout: 45 close(fd); 46 errno = err; 47 return -1; 48 }
服务器端:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <syslog.h> 5 #include <sys/socket.h> 6 #include <sys/select.h> 7 #include <netdb.h> 8 #include <errno.h> 9 10 #define BUFLEN 128 11 #define QLEN 10 12 13 #ifndef HOST_NAME_MAX 14 #define HOST_NAME_MAX 256 15 #endif 16 17 extern int initserver(int, struct sockaddr *, socklen_t , int); 18 19 void 20 serve(fd_set *sockset, int maxfd, int index, int fd_arr[]) 21 { 22 int clfd, listenfd; 23 int i; 24 int nready; 25 FILE *fp; 26 char buf[BUFLEN]; 27 28 for(;;) { 29 if((nready = select(maxfd+1, sockset, NULL, NULL, NULL)) > 0) { 30 for(i = 0; i < index; i++) { 31 listenfd = fd_arr[i]; 32 if(FD_ISSET(listenfd, sockset)) { 33 clfd = accept(listenfd, NULL, NULL); 34 35 if(clfd < 0) { 36 syslog(LOG_ERR, "ruptime: accept error:%s", 37 strerror(errno)); 38 exit(1); 39 } 40 41 if((fp = popen("/usr/bin/uptime", "r")) == NULL) { 42 sprintf(buf, "error:%s\n", strerror(errno)); 43 send(clfd, buf, strlen(buf), 0); 44 } else { 45 while(fgets(buf, BUFLEN, fp) != NULL) 46 send(clfd, buf, strlen(buf), 0); 47 pclose(fp); 48 } 49 close(clfd); 50 } 51 } 52 } 53 } 54 } 55 56 int 57 main(int argc, char *argv[]) 58 { 59 struct addrinfo *ailist, *aip; 60 struct addrinfo hint; 61 62 int sockfd, err, n; 63 int fd_arr[FD_SETSIZE]; 64 fd_set sockset; 65 int maxfd = -1; 66 int index = 0; 67 char *host; 68 69 if(argc != 1) { 70 printf("usage: ruptimed"); 71 exit(1); 72 } 73 74 #ifdef _SC_HOST_NAME_MAX 75 n = sysconf(_SC_HOST_NAME_MAX); 76 if(n < 0) 77 #endif 78 79 n = HOST_NAME_MAX; 80 host = malloc(n); 81 if(host == NULL) { 82 perror("malloc error"); 83 exit(1); 84 } 85 86 if(gethostname(host, n) < 0) { 87 perror("gethostname error"); 88 exit(1); 89 } 90 printf("in main pid: %d\n", getpid()); 91 92 daemonize("ruptimed"); 93 hint.ai_flags = AI_CANONNAME; 94 hint.ai_family = 0; 95 hint.ai_socktype = SOCK_STREAM; 96 hint.ai_protocol = 0; 97 hint.ai_addrlen = 0; 98 hint.ai_canonname = NULL; 99 hint.ai_next = NULL; 100 101 syslog(LOG_DEBUG, "ruptimed pid: %d\n", getpid()); 102 if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0) { 103 syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s", gai_strerror(err)); 104 exit(1); 105 } 106 107 FD_ZERO(&sockset); 108 memset(fd_arr, 0, sizeof(int)); 109 110 for(aip = ailist; aip != NULL; aip = aip->ai_next) { 111 syslog(LOG_DEBUG, "main port: %d\n", ntohs(((struct sockaddr_in *)aip->ai_addr)->sin_port)); 112 if((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN)) >= 0) { 113 if(sockfd > maxfd) 114 maxfd = sockfd; 115 FD_SET(sockfd, &sockset); 116 //serve(sockfd); 117 //exit(0); 118 fd_arr[index] = sockfd; 119 index++; 120 } 121 } 122 if(maxfd >= 0) { 123 serve(&sockset, maxfd, index, fd_arr); 124 } 125 exit(1); 126 }
注意:借用int数组fd_arr记录用于监听的套接字,在函数serve中,并不能确定较小数值套接字一定比较大数值套接字先准备好,所以
1 for (sockfd = 0; FD_ISSET(sockfd, sockfdsp); ++sockfd)
这样的循环是错误的。我这里用index记录套接字数量,fd_arr记录套接字,然后调用FD_ISSET遍历。
另外,在initserver函数中,调用了setsockopt,取消了TIME_WAIT的限制。