免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 17158 | 回复: 26
打印 上一主题 下一主题

在unix系统中创建守护进程 [复制链接]

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-05-07 13:36 |只看该作者 |倒序浏览
请大家讨论一下,在unix系统中如何创建daemon例程,通常又哪些步骤,哪些是关键的必不可少的步骤,为什么不能省略这些步骤?

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
2 [报告]
发表于 2003-05-07 15:23 |只看该作者

在unix系统中创建守护进程

这是论坛中的一段代码,大体上包含了创建一个守护进程的过程。


  1. void daemonize (servfd)
  2. int servfd;
  3. {
  4.   int childpid, fd, fdtablesize;
  5.   /* ignore terminal I/O, stop signals */
  6.    signal(SIGTTOU,SIG_IGN);
  7.    signal(SIGTTIN,SIG_IGN);
  8.    signal(SIGTSTP,SIG_IGN);
  9.   /* fork to put us in the background (whether or not the user
  10.    specified '&' on the command line */
  11.   if ((childpid = fork()) < 0) {
  12.     fputs("failed to fork first child\r\n",stderr);
  13.     exit(1);
  14.    }
  15.   else if (childpid >; 0)
  16.    exit(0); /* terminate parent, continue in child */
  17.    /* dissociate from process group */
  18.   if (setpgrp(0,getpid())<0) {
  19.     fputs("failed to become process group leader\r\n",stderr);
  20.     exit(1);
  21.   }
  22.   /* lose controlling terminal */
  23.   if ((fd = open("/dev/tty",O_RDWR)) >;= 0) {
  24.     ioctl(fd,TIOCNOTTY,NULL);
  25.     close(fd);
  26.   }
  27.   /* close any open file descriptors */
  28.   for (fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++)
  29.   if (fd != servfd)
  30.    close(fd);
  31.    /* set working directory to allow filesystems to be unmounted */
  32.    chdir("/");
  33.    /* clear the inherited umask */
  34.    umask(0);
  35.    /* setup zombie prevention */
  36.    signal(SIGCLD,(Sigfunc *)reap_status);
  37.   }
复制代码

论坛徽章:
0
3 [报告]
发表于 2003-05-07 15:28 |只看该作者

在unix系统中创建守护进程

我家里有本书《Linux网络编程》上全都有,现在封校,找不到确切答案,大概是这么做,记不清了。


  1. .....
  2. .....
  3. pid=fork();
  4. if (pid>;0) {
  5.   printf("subprocess %d forked.\n",pid);
  6.   exit(0);
  7. } elseif (pid<0) {
  8.   printf("ERROR!\n");
  9.   exit(0);
  10. }

  11. setsid();
  12. signal(SIGHUP,SIGIGN);

  13. pid=fork();
  14. if (pid>;0) {
  15.   printf("daemon process %d forked.\n",pid);
  16.   exit(0);
  17. }elseif (pid<0) {
  18.   printf("ERROR!\n");
  19.   exit(0);
  20. }

  21. fcloseall();

  22. fd=open("/dev/null","r");
  23. dup2(fd,0);
  24. fd=open("/...../logfile","a");
  25. dup2(fd,1);
  26. dup2(fd,2);
  27. ......
  28. ......
复制代码

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
4 [报告]
发表于 2003-05-07 15:46 |只看该作者

在unix系统中创建守护进程

1、调用函数fork()创建子进程,然后父进程终止,保留子进程继续运行。之所以要让父进程终止是因为,当一个进程是以前台进程方式由shell启动时,在父进程终止之后子进程自动转为后台进程。另外,我们在下一步要创建一个新的会晤期,这就要求创建会晤期的进程不是一个进程组的组长进程。当父进程终止,子进程运行,这就保证了进程组的组ID与子进程的进程ID不会相等。

或者

使用 setsid 设置为新会话的领头进程,因为 setsid 要求调用进程不是会话的领头进程时才有效.因此, 首先可用 fork 派生, 并结束父进程.之后调用 setsid, 子进程成为新会话的领头进程, 从而与原有会话, 进程组, tty 脱离.但是, 为避免作为新会话领头进程的子进程在打开一个终端设备时, 拥有一个控制终端.再次派生, 并结束父进程, 可让子进程成为非会话领头进程.
    if (fork ())
        exit (0);
   
    setsid ();

    if (fork ())
        exit (0);

2、信号处理,包括处理 SIGCHLD 信号, 为避免形成僵尸进程。

3、关闭不再需要的文件描述符,并为标准输入、标准输出和标准错误输出打开新的文件描述符(也可以继承父进程的标准输入、标准输出和标准错误输出文件描述符,这个操作是可选的)。
例如:
for (i=0; i < NOFILE; i++) close (i);

4、调用函数chdir("/"将当前工作目录更改为根目录。这是为了保证我们的进程不使用任何目录。否则我们的守护进程将一直占用某个目录,这可能会造成超级用户不能卸载一个文件系统。

5、调用函数umask(0)将文件方式创建屏蔽字设置为"0"。这是因为由继承得来的文件创建方式屏蔽字可能会禁止某些许可权。例如我们的守护进程需要创建一组可读可写的文件,而此守护进程从父进程那里继承来的文件创建方式屏蔽字却有可能屏蔽掉了这两种许可权,则新创建的一组文件其读或写操作就不能生效。因此要将文件方式创建屏蔽字设置为"0"。

论坛徽章:
0
5 [报告]
发表于 2003-05-07 16:11 |只看该作者

在unix系统中创建守护进程

[quote]原帖由 "蓝色键盘"]1.2.3.4.5[/quote 发表:

1.2.3
是我经常做的
4.5没做过

受益非浅!
收藏!

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
6 [报告]
发表于 2003-05-07 17:04 |只看该作者

在unix系统中创建守护进程

一段完整的守护进程的代码,有兴趣的可以测试一下。建议收藏。

  1. #include <stdio.h>;
  2. #include <fcntl.h>;
  3. #include <signal.h>;
  4. #include <unistd.h>;

  5. #define RUNNING_DIR        "/tmp"
  6. #define LOCK_FILE        "exampled.lock"
  7. #define LOG_FILE        "exampled.log"

  8. void log_message(filename,message)
  9. char *filename;
  10. char *message;
  11. {
  12. FILE *logfile;
  13.         logfile=fopen(filename,"a");
  14.         if(!logfile) return;
  15.         fprintf(logfile,"%s\n",message);
  16.         fclose(logfile);
  17. }

  18. void signal_handler(sig)
  19. int sig;
  20. {
  21.         switch(sig) {
  22.         case SIGHUP:
  23.                 log_message(LOG_FILE,"hangup signal catched");
  24.                 break;
  25.         case SIGTERM:
  26.                 log_message(LOG_FILE,"terminate signal catched");
  27.                 exit(0);
  28.                 break;
  29.         }
  30. }

  31. void daemonize()
  32. {
  33. int i,lfp;
  34. char str[10];
  35.         if(getppid()==1) return; /* already a daemon */
  36.         i=fork();
  37.         if (i<0) exit(1); /* fork error */
  38.         if (i>;0) exit(0); /* parent exits */
  39.         /* child (daemon) continues */
  40.         setsid(); /* obtain a new process group */
  41.         for (i=getdtablesize();i>;=0;--i) close(i); /* close all descriptors */
  42.         i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standart I/O */
  43.         umask(027); /* set newly created file permissions */
  44.         chdir(RUNNING_DIR); /* change running directory */
  45.         lfp=open(LOCK_FILE,O_RDWR|O_CREAT,0640);
  46.         if (lfp<0) exit(1); /* can not open */
  47.         if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* can not lock */
  48.         /* first instance continues */
  49.         sprintf(str,"%d\n",getpid());
  50.         write(lfp,str,strlen(str)); /* record pid to lockfile */
  51.         signal(SIGCHLD,SIG_IGN); /* ignore child */
  52.         signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
  53.         signal(SIGTTOU,SIG_IGN);
  54.         signal(SIGTTIN,SIG_IGN);
  55.         signal(SIGHUP,signal_handler); /* catch hangup signal */
  56.         signal(SIGTERM,signal_handler); /* catch kill signal */
  57. }

  58. main()
  59. {
  60.         daemonize();
  61.         while(1) sleep(1); /* run */
  62. }

复制代码



1、编译cc -o exampled examped.c
2、运行./exampled
3、测试daemon进程
ps -ef|grep exampled (or ps -aux on BSD systems)
4、log
tail -f /tmp/exampled.log
5、测试signal
kill -HUP `cat /tmp/exampled.lock`
6、终止
kill `cat /tmp/exampled.lock`

论坛徽章:
0
7 [报告]
发表于 2003-05-07 20:05 |只看该作者

在unix系统中创建守护进程

用2个fork是对的,用一个fork会产生子进程已经死而父进程还活跃的情况下回不释放子进程的proc结构!

论坛徽章:
0
8 [报告]
发表于 2003-05-07 22:46 |只看该作者

在unix系统中创建守护进程

为什么守护进程要脱离终端(shell)?

我看到一些守护进程没有脱离终端SHELL, 即 PPID=SHELL pid.

谁说一下在什么情况下会有严重后果?

论坛徽章:
0
9 [报告]
发表于 2003-05-07 22:51 |只看该作者

在unix系统中创建守护进程

还有, 关闭 fd0,1,2是必须的吗?

我们可以后台运行一个程序 ---(前台运行没有什么意义嘛, 除了测试)

MyProgam -D -c conf.cfg >;m.log 2>;&1 &

论坛徽章:
0
10 [报告]
发表于 2003-05-08 07:52 |只看该作者

在unix系统中创建守护进程

原帖由 "nile" 发表:
为什么守护进程要脱离终端(shell)?

我看到一些守护进程没有脱离终端SHELL, 即 PPID=SHELL pid.

谁说一下在什么情况下会有严重后果?

我想应该是这样的:如果不脱离终端。在退出终端时,包含守护进程的会话会终止。自然守护进程也就随之终止了。不能保证长期稳定运行。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP