守护进程

#include <unistd.h>

pid_t setsid(void);   //创建一新的Session并且自己成为Session的Leader。

该函数调用成功时返回新创建的Session的id(也就是当前进程的ID),出错返回-1;

调用这个函数之前,当前进程不允许是进程组的leader否则会出错返回-1.

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

以下转载自知乎:作者 贾小宇

Linux Daemon(守护进程)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对某个用户程序提供服务。Linux系统的大多数服务器就是通过守护进程实现的。常见的守护进程包括系统日志进程syslogd、 web服务器httpd、邮件服务器sendmail和数据库服务器mysqld等。

创建守护进程的的一般步骤:

1、fork()创建子进程,父进程exit()退出

这是创建守护进程的第一步。由于守护进程是脱离控制终端的,因此,完成第一步后就会在Shell终端里造成程序已经运行完毕的假象。
之后的所有工作都在子进程中完成,而用户在Shell终端里则可以执行其他命令,从而在形式上做到了与控制终端的脱离,在后台工作。


2、在子进程中调用 setsid() 函数创建新的会话

在调用了 fork() 函数后,子进程全盘拷贝了父进程的会话期、进程组、控制终端等,虽然父进程退出了,但会话期、进程组、控制终端等并没有改变,
因此,这还不是真正意义上的独立开来,而 setsid() 函数能够使进程完全独立出来。


3、再次 fork() 一个子进程并让父进程退出。

现在,进程已经成为无终端的会话组长,但它可以重新申请打开一个控制终端,可以通过 fork() 一个子进程,
该子进程不是会话首进程,该进程将不能重新打开控制终端。退出父进程。


4、在子进程中调用 chdir() 函数,让根目录 ”/” 成为子进程的工作目录

这一步也是必要的步骤。使用fork创建的子进程继承了父进程的当前工作目录。由于在进程运行中,
当前目录所在的文件系统(如“/mnt/usb”)是不能卸载的,这对以后的使用会造成诸多的麻烦(比如系统由于某种原因要进入单用户模式)。
因此,通常的做法是让"/"作为守护进程的当前工作目录,这样就可以避免上述的问题,
当然,如有特殊需要,也可以把当前工作目录换成其他的路径,如/tmp。改变工作目录的常见函数是chdir。


5、在子进程中调用 umask() 函数,设置进程的文件权限掩码为0

文件权限掩码是指屏蔽掉文件权限中的对应位。比如,有个文件权限掩码是050,它就屏蔽了文件组拥有者的可读与可执行权限。
由于使用fork函数新建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带来了诸多的麻烦。
因此,把文件权限掩码设置为0,可以大大增强该守护进程的灵活性。设置文件权限掩码的函数是umask。在这里,通常的使用方法为umask(0)。


6、在子进程中关闭任何不需要的文件描述符

同文件权限码一样,用fork函数新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读写,
但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下。
在上面的第二步之后,守护进程已经与所属的控制终端失去了联系。因此从终端输入的字符不可能达到守护进程,
守护进程中用常规方法(如printf)输出的字符也不可能在终端上显示出来。所以,文件描述符为0、1和2 的3个文件(常说的输入、输出和报错)已经失去了存在的价值,也应被关闭。


7、守护进程退出处理

当用户需要外部停止守护进程运行时,往往会使用 kill 命令停止该守护进程。
所以,守护进程中需要编码来实现 kill 发出的signal信号处理,达到进程的正常退出。

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

8、示例代码

istd.h>


void init_mydaemon(void)
{
    struct sigaction sa;
     pid_t pid;


// 1.创建子进程,父进程退出,让子进程创建新的session。
   if((pid=fork())>0)
   {
       _exit(0);
   }
   else if(pid<0)
   {
       perror("fork");
        return;
   }


   setsid();
//2. 设置信号捕捉函数,捕捉SIG_CHLD,这样以后守护进程创建的子进程均不用被等待。
   sa.sa_handler = SIG_IGN;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags=0;
    sigaction(SIGHUP, &sa, NULL);


//3.再次创建子进程,并让父进程退出。
    if((pid=fork())>0)
    {
      _exit(0);
    }
    else if(pid<0)
    {
        perror("fork2");
        return;
    }
//4.改变当前目录为根目录。
    if(chdir("/")<0)
    {
        printf("change dirction error!\n");
        return;
    }
//5.设置文件屏蔽字
     umask(0);
//6.关掉之前的文件描述符。
     close(0);
    int fd=open("/dev/null", O_RDWR); 
    dup2(fd,1);
    dup2(fd,2);






}
int main()
{
  init_mydaemon();
//  daemon(0,0);
  while(1)
  {
      sleep(1);
  }
}

关于:系统提供的daemon函数。

第一个参数设置为零表示 改变当前工作目录为根目录,第二个参数设置为零,表示重定向 标准输入、标准输出、标准错误到/dev/null文件中。

如果两个参数为非零值,则表示不对工作目录和标准输入、输出、错误的文件描述符做任何处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值