守护进程

守护进程
进程组是一组进程的集合,进程组由进程组PID表示
每个进程除了进程id之外,还必须有一个进程组id,即必须属于某个进程组
每个进程组都有一个组长,其进程id就作为进程组id,它不受进程组长的退出影响
一般来说,一个终端一般是进程组长。

会话期是由一个或多个进程组组成的集合
一个会话期开始于用户登录,结束于用户退出。在此期间用户运行的的所有进程都属于这个会话期。

创建守护进程基本步骤
1.创建子进程
在终端输入命令执行用户程序时,该进程成为父进程,它此时受控制终端即创建该进程的控制终端控制,通过它创建子进程
让子进程脱离该终端的控制:子进程执行守护进程需要执行的代码,然后让父进程退出,此时子进程的父进程变为了系统的Init进程。
当父进程先于子进程退出,子进程成为孤儿进程。
在linux系统中,每当系统发现一个孤儿进程后,就会自动由1号进程(init进程) 收养它。
每个进程在创建时都有其自身的进程组、会话期及所属的控制终端,当创建子进程时,子进程复制父进程的这些属性,因此父子进程属于同一个进程组、会话期及控制终端
2.让子进程脱离该终端的控制。当执行setsid()系统调用,使其脱离原终端控制。它创建一个新的会话并让调用它的进程成为该会话的组长,主要的3个作用
2.1 让进程摆脱原会话的控制
2.2 让进程摆脱原进程组的控制
2.3 让进程摆脱原控制终端的控制
setsid()系统调用
3.改变当前目录为根目录
每个进程在执行时,都保存当前执行目录的信息。子进程也继承父进程的该信息
由于在进程运行过程中,当前目录所在的文件系统是不能卸载的,
这对以后的使用会造成诸多的麻烦(如用户要对不使用的目录进行卸载操作,由于该目录还在被守护进程使用,所以umount出错,导致该目录不能被卸载)
通常的做法是让系统根目录"/" 作为守护进程的的当前工作目录,会避免上述不必要的问题。当然,如果有特殊需要也可以把当前工作目录换成其它的路劲
4.修改文件权限掩码
文件掩码是指屏蔽掉文件权限中的对应位。比如,一个文件的权限掩码是050,其对应的二进制码为000101000 表示屏蔽文件用户组用户读和执行的权限
由于新建子进程继承父进程的文件权限掩码,这就给该子进程操作文件带来诸多麻烦,因此,把文件权限掩码设置成0,即取消子进程对文件操作的限制,
从而大大增强该守护进程的灵活性,即调用umask(0)
5.关闭文件描述符
同文件掩码一样,新建的子进程从父进程继承已经打开的文件描述符。这些被打开的文件描述符可能永远不会被守护进程读写,但它们同样耗费系统资源,
而且可能导致文件系统无法卸载。既然守护进程与控制终端失去了联系,因此与控制终端相关的文件描述符就不会被使用,如:文件描述符为 0,1,2(输入,输出和出错)
等文件描述符就不会被使用,失去存在的意义,要关闭它们,可使用close(fd)方法

示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.h>

#define MAXFILE 65535
char *timestr();
int main(){
    pid_t pc;
    char wtr[100];
    int i,fd,len;
    char *buf ="hello everybody!";
    len=strlen(buf);
    pc=fork();
    if(pc<0){
        printf("fork err\n");
        exit(1);
    }
    if(pc>0) exit(0);
    

    setsid();
    chdir("/");
    umask(0);
    for(i=0;i<MAXFILE;i++){
        while(1){
            if(fd= open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600)<0){
                perror("open");
                exit(1);
            }
            sprintf(wtr, "%s-%s\n",buf,timestr());
            write(fd,wtr,strlen(wtr)+1);
            close(fd);
            sleep(2);
        }
        
    }
}

char *timestr(){
    time_t timep;
    static char timestr[50];
      struct tm *p;
      time(&timep);
      p = gmtime(&timep);
      sprintf(timestr,"%d:%d:%d", p->tm_hour, p->tm_min, p->tm_sec);
      return timestr;
}

运行后

[root@centos1 c]# ./daemon
hello everybody!-11:39:41
[root@centos1 c]# ^C
[root@centos1 c]# tail -f /tmp/daemon.log
hello everybody!-11:39:43
hello everybody!-11:39:45
hello everybody!-11:39:47
hello everybody!-11:39:49
hello everybody!-11:39:51
hello everybody!-11:39:53
hello everybody!-11:39:55

 

目标

创建新会话

头文件

#include <unistd.h>;#include <sys/types.h>

函数原型

pid_t pid=setsid(void)

返回值

出错,返回-1

成功,返回该进程组的pid

posted @ 2018-05-27 19:53  H&K  阅读(388)  评论(0编辑  收藏  举报