首页 > 代码库 > APUE16章的运行示例16-14

APUE16章的运行示例16-14

参考文章:http://blog.csdn.net/andyxie407/article/details/1672325

今天在运行在APUE第16章的16-14(客户端)和16-15(服务端)遇到了不少问题,搞了半天,运行方法多谢andyxie407的文章给了很好地参考(本来就一样,不叫参考),后面还是运行不出结果,结果找到了两个程序抄错了的地方(原谅我,有时候,看一眼大概实现就把代码敲上去了),写都写到这了,还是把我的痛苦运行结果展示一番,代码如下:

 

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. //16-14.c 即客户端  
  2. #include "apue.h"  
  3. #include <netdb.h>  
  4. #include <errno.h>  
  5. #include <sys/socket.h>  
  6.   
  7. #define MAXADDRLEN 256  
  8. #define BUFLEN 128  
  9.   
  10. #define MAXSLLEP 128  
  11. int connect_retry(int sockfd, struct sockaddr *addr, socklen_t alen)  
  12. {  
  13.     int nsec;  
  14.   
  15.     for ( nsec = 1; nsec < MAXSLLEP; nsec <<= 1) {//nsec <<= 1 equal to nsec = nsec << 1 equal to nsec /= 2;  
  16.         if (connect(sockfd, addr, alen) == 0)  
  17.             return 0;  
  18.         if (nsec <= MAXSLLEP/2)  
  19.             sleep(nsec);  
  20.     }  
  21.     return -1;  
  22. }  
  23.   
  24. void print_uptime(int sockfd)  
  25. {  
  26.     char    buf[BUFLEN];  
  27.     int     n;  
  28.   
  29.     while ((n = recv(sockfd, buf, BUFLEN, 0)) > 0)  
  30.         write(STDOUT_FILENO, buf, n);  
  31.     if (n < 0)  
  32.         err_sys("recv error");  
  33. }  
  34.   
  35. int main(int argc, char *argv[])  
  36. {  
  37.     struct addrinfo *aip, *ailist;  
  38.     struct addrinfo hint;  
  39.     int     err, sockfd;  
  40.   
  41.     if (argc != 2)   
  42.         err_quit("Usage: ruptime hostname");  
  43.     hint.ai_family      = 0;  
  44.     hint.ai_flags       = 0;//AI_CANONNAME;  
  45.     hint.ai_socktype    = SOCK_STREAM;  
  46.     hint.ai_protocol    = 0;  
  47.     hint.ai_addrlen     = 0;  
  48.     hint.ai_canonname   = NULL;  
  49.     hint.ai_addr        = NULL;  
  50.     hint.ai_next        = NULL;  
  51.   
  52.     if ((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)  
  53.         err_quit("getaddrinfo:%s", gai_strerror(err));  
  54.     for (aip = ailist; aip != NULL; aip = aip->ai_next) {  
  55.         if ((sockfd = socket(aip->ai_family, SOCK_STREAM, 0)) < 0) {  
  56.             err = errno;  
  57.         }  
  58.         if (connect_retry(sockfd, aip->ai_addr, aip->ai_addrlen) < 0)  
  59.             err = errno;  
  60.         else {  
  61.             printf("connect to ruptime server successfully !\n");  
  62.             print_uptime(sockfd);  
  63.             exit(0);  
  64.         }  
  65.     }  
  66.     fprintf(stderr, "cannot connect to %s:%s\n", argv[1], strerror(err));  
  67.     exit(1); //err happened  
  68. }  
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. //16-15.c即服务端  
  2. #include "apue.h"  
  3. #include <netdb.h>  
  4. #include <syslog.h>  
  5. #include <errno.h>  
  6. #include <sys/socket.h>  
  7.   
  8. #define BUFLEN  128  
  9. #define QLEN    10  
  10.   
  11. #ifndef HOST_NAME_MAX  
  12. #define HOST_NAME_MAX 256  
  13. #endif  
  14.   
  15. int init_server(int type, struct sockaddr *addr, socklen_t alen, int qlen)  
  16. {  
  17.     int fd, err = 0;  
  18.   
  19.     if ((fd = socket(addr->sa_family, type, 0)) < 0)   
  20.         return -1;  
  21.     if (bind(fd, addr, alen) < 0) {  
  22.         err = errno;  
  23.         goto errout;  
  24.     }  
  25.     if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {  
  26.         if (listen(fd, QLEN) < 0) {  
  27.             err = errno;  
  28.             goto errout;  
  29.         }  
  30.     }  
  31.     return fd;      //successful when prog arrive here.  
  32.   
  33. errout:  
  34.     close(fd);      //exit with failuare  
  35.     errno = err;  
  36.     return -1;  
  37. }  
  38.   
  39. void serve(int fd)  
  40. {  
  41.     char    buf[BUFLEN];  
  42.     int     clfd;  
  43.     FILE    *fp;  
  44.   
  45.     for ( ; ; ) {  
  46.         if ((clfd = accept(fd, NULL, NULL)) < 0) {  
  47.             syslog(LOG_ERR, "ruptime: accept error:%s", strerror(errno));  
  48.             exit(1);  
  49.         }  
  50.         if ((fp = popen("/usr/bin/uptime", "r")) == NULL) {  
  51.             sprintf(buf, "error:%s\n", strerror(errno));  
  52.             send(clfd, buf, strlen(buf), 0);  
  53.         } else {  
  54.             while (fgets(buf, BUFLEN, fp) != NULL)  
  55.                 send(clfd, buf, strlen(buf), 0);  
  56.             pclose(fp);  
  57.         }  
  58.         close(clfd); //send end  
  59.     }  
  60. }  
  61.   
  62. int main(int argc, char *argv[])  
  63. {  
  64.     struct addrinfo *ailist, *aip;  
  65.     struct addrinfo hint;  
  66.     int     err, sockfd, n;  
  67.     char    *host;  
  68.   
  69.     if (argc != 1)  
  70.         err_quit("Usage:service");  
  71.   
  72. #ifdef _SC_HOST_NAME_MAX  
  73.     n = sysconf(_SC_HOST_NAME_MAX);  
  74.     if (n < 0)  
  75. #endif  
  76.         n = HOST_NAME_MAX;  
  77.     host = malloc(n);  
  78.     if (!host)  
  79.         err_sys("malloc error");  
  80.     if (gethostname(host, n) < 0)  
  81.         err_sys("gethostname");  
  82.     printf("host name is:%s\n", host);  
  83.     daemonize("ruptimed");  
  84.   
  85.     hint.ai_flags       = AI_CANONNAME;  
  86.     hint.ai_family      = 0;  
  87.     hint.ai_socktype    = SOCK_STREAM;  
  88.     hint.ai_protocol    = 0;  
  89.     hint.ai_addrlen     = 0;  
  90.     hint.ai_canonname   = NULL;  
  91.     hint.ai_addr        = NULL;  
  92.     hint.ai_next        = NULL;  
  93.   
  94.     if ((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0) {  
  95.         syslog(LOG_ERR , "ruptime:getaddrinfo error:%s", gai_strerror(err));  
  96.         exit(1);  
  97.     }  
  98.   
  99.     for (aip = ailist; aip != NULL; aip = aip->ai_next) {  
  100.         sockfd = init_server(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN);   
  101.         if (sockfd >= 0){  
  102.             serve(sockfd);  
  103.             exit(0);  
  104.         }  
  105.     }  
  106.     exit(1);  
  107. }  

分别编译成可执行文件,然后运行服务端 ./ruptimed,可以通过/var/log/syslog看到发生了错误

Servname not supported for ai_socktype .

解决方法之一:先到/etc/services中添加如下内容

ruptime 4000/tcp

保存离开,但是你要确保4000这个端口没有被其他服务占用,否则改用其他端口。这时先运行

$./ruptimed

这是16-15编译出的名字,可以通过ps -ef 看到刚才的程序已成为后台程序,再运行

$./ruptime ubuntu

前面那个是16-14编译出的名字,后面那个是用户/主机名(前面有篇文章讲到了,但是这里不能用localhost或127.0.0.1

得到结果。

12:06:45 up 21:40,  2 users,  load average: 0.00, 0.01, 0.05

很兴奋有木有!

还有一种方法不用更改/etc/services的方法,是将程序中的服务名改成端口号,然后改些其他内容,详见参考文章!

顺便提醒自己一句:在你不能保证自己程序的正确性时(即便编译通过不能代表没有写错或写漏一些东西),先不要到处找程序之外的任何原因,谨记!

APUE16章的运行示例16-14