免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 24610631 | 回复: 24610631

[C] APUE上的daemonize和ruptimed [复制链接]

论坛徽章:
1
亥猪
日期:2013-10-30 23:29:55
发表于 2012-10-02 23:33 |显示全部楼层
在APUE中,daemonize函数用于初始化一个守护进程,在这个过程中,经历两次fork,同时两次退出父进程。ruptimed函数调用daemonize函数,我觉得调用daemonize函数的进程退出,所以ruptimed里面位于daemonize之后的代码都不会被执行,但明显这不是作者的原意,但我又找不出我思路错误的原因,还清各位指点。
daemonize函数:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <syslog.h>
  5. #include <fcntl.h>
  6. #include <sys/resource.h>
  7. #include <signal.h>

  8. void
  9. daemonize(const char * cmd)
  10. {
  11.         int i, fd0, fd1, fd2;
  12.         pid_t pid;
  13.         struct rlimit rl;
  14.         struct sigaction sa;

  15.         /*
  16.          *clear file creation mask;
  17.          */

  18.         umask(0);

  19.         /*
  20.          * get maxmum number of file descriptors;
  21.          */

  22.         if(getrlimit(RLIMIT_NOFILE, &rl) < 0) {
  23.                 printf("%s can't get file limit", cmd);
  24.                 exit(1);
  25.         }

  26.         /*
  27.          *become a session leader to lose controlling TTY;
  28.          */

  29.         if((pid = fork()) < 0) {
  30.                 perror("fork error");
  31.                 exit(1);
  32.         } else if(pid != 0)
  33.                 exit(0);

  34.         printf("child1");
  35.         setsid();

  36.         sa.sa_handler = SIG_IGN;
  37.         sigemptyset(&sa.sa_mask);
  38.         sa.sa_flags = 0;
  39.         if(sigaction(SIGHUP, &sa, NULL) < 0) {
  40.                 perror("sigaction error");
  41.                 exit(1);
  42.         }

  43.         if((pid = fork()) < 0) {
  44.                 perror("fork error");
  45.                 exit(1);
  46.         } else if(pid != 0)
  47.                 exit(0);
  48.         printf("child2");

  49.         if(chdir("/") < 0)
  50.                 perror("can't change directory to /");

  51.         if(rl.rlim_max == RLIM_INFINITY)
  52.                 rl.rlim_max = 1024;
  53.         for(i = 0; i < rl.rlim_max; i++)
  54.                 close(i);

  55.         fd0 = open("/dev/null", O_RDWR);
  56.         fd1 = dup(0);
  57.         fd2 = dup(0);

  58.         /*
  59.          * initialize the log file
  60.          */
  61.         openlog(cmd, LOG_CONS, LOG_DAEMON);
  62.         if(fd0 != 0 || fd1 != 1 || fd2 != 2) {
  63.                 syslog(LOG_ERR, "unexpected descriptors %d %d %d", fd0, fd1, fd2);
  64.                 exit(1);
  65.         }
  66. }
复制代码
ruptimed函数:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <syslog.h>
  5. #include <sys/socket.h>
  6. #include <netdb.h>
  7. #include <errno.h>

  8. #define BUFLEN 128
  9. #define QLEN 10

  10. #ifndef HOST_NAME_MAX
  11. #define HOST_NAME_MAX 256
  12. #endif

  13. extern int initserver(int, struct sockaddr *, socklen_t , int);

  14. void
  15. serve(int sockfd)
  16. {
  17.         int clfd;
  18.         FILE *fp;
  19.         char buf[BUFLEN];

  20.         for(;;) {
  21.                 clfd = accept(sockfd, NULL, NULL);
  22.                 if(clfd < 0) {
  23.                         syslog(LOG_ERR, "ruptime: accept error:%s",
  24.                                         strerror(errno));
  25.                         exit(1);
  26.                 }
  27.                 if((fp = popen("/usr/bin/uptime", "r")) == NULL) {
  28.                         sprintf(buf, "error:%s\n", strerror(errno));
  29.                         send(clfd, buf, strlen(buf), 0);
  30.                 } else {
  31.                         while(fgets(buf, BUFLEN, fp) != NULL)
  32.                                 send(clfd, buf, strlen(buf), 0);
  33.                         pclose(fp);
  34.                 }
  35.                 close(clfd);
  36.         }
  37. }

  38. int
  39. main(int argc, char *argv[])
  40. {
  41.         struct addrinfo *ailist, *aip;
  42.         struct addrinfo hint;

  43.         int sockfd, err, n;
  44.         char *host;

  45.         if(argc != 1) {
  46.                 printf("usage: ruptimed");
  47.                 exit(1);
  48.         }

  49. #ifdef _SC_HOST_NAME_MAX
  50.         n = sysconf(_SC_HOST_NAME_MAX);
  51.         if(n < 0)
  52. #endif

  53.         n = HOST_NAME_MAX;
  54.         host = malloc(n);
  55.         if(host == NULL) {
  56.                 perror("malloc error");
  57.                 exit(1);
  58.         }

  59.         if(gethostname(host, n) < 0) {
  60.                 perror("gethostname error");
  61.                 exit(1);
  62.         }
  63.         printf("host : %s\n", host);
  64.         printf("pid: %d\n", getpid());

  65.         daemonize("ruptimed");
  66.         [color=Red]printf("pid: %d\n", getpid());
  67.         hint.ai_flags = AI_CANONNAME;
  68.         hint.ai_family = 0;
  69.         hint.ai_socktype = SOCK_STREAM;
  70.         hint.ai_protocol = 0;
  71.         hint.ai_addrlen = 0;
  72.         hint.ai_canonname = NULL;
  73.         hint.ai_next = NULL;

  74.         printf("--------------\n");
  75.         if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0) {
  76.                 syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s", gai_strerror(err));
  77.                 exit(1);
  78.         }
  79.         printf("--------------\n");
  80.         for(aip = ailist; aip != NULL; aip = aip->ai_next) {
  81.                 if((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN)) >= 0) {
  82.                         serve(sockfd);
  83.                         exit(0);
  84.                 }
  85.         }
  86.         exit(1);[/color]
  87. }
复制代码
也就是说红色部分的代码都不会再执行,因为当前进程作为daemonize中的父进程已经退出。

论坛徽章:
1
亥猪
日期:2013-10-30 23:29:55
发表于 2012-10-02 23:52 |显示全部楼层
本帖最后由 suanmeilizhi 于 2012-10-02 23:54 编辑

好吧,我二了,fork之后子进程和父进程共享正文段,所以即使父进程退出,子进程还是会按照父进程的正文执行下去。现在还没懂的是守护进程在此处的意义。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
发表于 2012-10-03 10:05 |显示全部楼层
本帖最后由 linux_c_py_php 于 2012-10-03 11:14 编辑

守护进程脱离终端了, 在新的会话里边, 在你的shell(该shell是你当前会话首进程)里看起来就像是“跑到后台”(实际上, 这里与后台没有半毛钱关系)去了一样, 你可以继续做其他事了.

这个程序的先守护, 打开syslog, 之后getaddrinfo获取ruptime服务的TCP监听端口(依赖/etc/services的服务, 最好hint设置AI_PASSIVE,否则需要获取后对sin_addr赋值).

最后循环每一个监听端口, 调用initserver启动监听.

可以猜得出来, initserver是需要调用fork/pthread_create的, 否则没法同时监听N个端口.

论坛徽章:
1
亥猪
日期:2013-10-30 23:29:55
发表于 2012-10-03 10:39 |显示全部楼层
回复 3# linux_c_py_php


    我在/etc/services中添加了内容
  1. 4000 ruptime/tcp
复制代码
所以监听的是4000这个端口,和IP绑定为0有什么关系,不懂,麻烦您指教哈。
    另外,最后一个循环只监听了一个。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
发表于 2012-10-03 11:14 |显示全部楼层
IP绑0就是绑INADDR_ANY的意思, initserver里struct sockaddr_in结构体的sin_addr赋值过吗.

正确的做法应该是:hint的flag要加上AI_PASSIVE,这样才会将结果的sockaddr_in.sin_addr = 0,这样就默认监听在所有IP上了。 如果不用这个,你需要给结果的sin_addr进行赋值。

论坛徽章:
1
亥猪
日期:2013-10-30 23:29:55
发表于 2012-10-03 22:26 |显示全部楼层
回复 5# linux_c_py_php


initserver函数的作用是绑定和监听套接字。   
我在服务器端的hint.ai_flags设置为AI_CANONNAME,是不是说initserver函数sockaddr_in.sin_addr就没有自动设为0,导致服务器并没有监听所有IP,系统选一个地址并将其绑定到套接字呢?

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
发表于 2012-10-03 22:32 |显示全部楼层
按道理说是未定义的, 看返回的sin_addr是什么随机值了, 反正错误的IP是bind失败的.

论坛徽章:
1
亥猪
日期:2013-10-30 23:29:55
发表于 2012-10-03 23:12 |显示全部楼层
回复 7# linux_c_py_php


    谢谢指教,感觉还是有很多不懂的地方,还需要加强。
    刚刚试了一下,发现在服务器端过滤之后的地址端口并不是我添加在/etc/services中的4000,请问这是怎么回事?

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
发表于 2012-10-03 23:53 |显示全部楼层
4000 ruptime/tcp

改成:

ruptime 4000/tcp

论坛徽章:
1
亥猪
日期:2013-10-30 23:29:55
发表于 2012-10-04 10:08 |显示全部楼层
回复 9# linux_c_py_php


    额。。。是我抄错了。。。
在/etc/services里面我是这样写的,ruptime 4000/tcp
但是结果确实40957
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP