1. 用户信息
- 真实用户ID ( UID )
- 有效用户ID ( EUID )
- 真实组ID ( GID )
- 有效组ID ( EGID )
一个进程有两个用户 ID :UID 和 EUID 。
EUID 存在的目的是方便资源访问 :它使得运行程序的用户拥有该程序的有效用户的权限
2. 进程组
是一个或多个进程的集合
Linux下每个进程都属于一个进程组,因此除了 PID 信息外,还有进程组ID( PGID )
每个进程组都有一个首领进程,其PGID和PID相同。进程组将一直存在,直到其中所有进程都退出,或者加入到其他进程组
#include <unistd.h>
pid_t getpgid(pid_t pid);//获取指定进程的pid
int setpgid(pid_t pid, pid_t pgid );//将PID为pid的进程的PGID设置为pgid
3.会话
会话是一个或多个进程组的集合。通常,一个会话开始于用户登录,终止于用户退出,在此期间,该用户运行的所有进程都属于这个会话
#include <unistd.h>
pid_t setsid(void) //创建一个会话
只有非组首领进程可调用该函数,会有如下效果
- 调用进程成为会话的首领,此时该进程是新会话的唯一成员
- 新建一个进程组,其 PGID 就是调用进程的 PID ,调用进程成为该组的首领
- 调用进程将甩开终端
执行 ps 命令可查看进程、进程组和会话之间的关系
ps -o pid,ppid,pgid,sid,comm | less
4. 守护进程
守护进程是脱离于终端并在后台运行的进程
脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示,并且进程也不会被任何终端所产生的终端信息所打断
创建守护进程步骤:
- 创建子进程,父进程退出
使其成孤儿进程,由1号进程( init 进程 )收养 - 在子进程中创建新会话
使用系统函数 setsid ( ) , 3个作用:进程摆脱原会话的控制;摆脱原进程组的控制;摆脱原控制终端的控制 - 改变当前目录为根目录
#include <unistd.h>
int chdir(const char* path );//path指向要切换的工作目录
//通常让 "/" 作为守护进程的当前工作目录
- 重设文件权限掩码
屏蔽掉文件权限中的对应位,通常使用 umask ( 0 ); - 关闭文件描述符
关闭继承过来的打开了的文件,不会被守护进程读写但占用资源
也关闭文件描述符为0、1、2(输入、输出、报错)的三个文件
例:
实现一个守护进程,每10秒在 /tmp/dameon.log 中写入一句话
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAXFILE 65535
int main(){
pid_t pc;
int i,fd,len;
char* buf = "this is a Dameon\n";
len = strlen(buf);
pc = fork(); // 第一步
if(pc<0){
printf("error fork\n");
exit(1);
}else if(pc > 0){
exit(0);
}
//exit(0):正常运行程序并退出程序;
//exit(1):非正常运行导致退出程序;
setsid(); //第二步
chdir("/"); //第三步
umask(0); //第四步}
for(i=o;i<MAXFILE;i++){ //第五步
close(i);
}
while(1){
if(fd = open("/tmp/dameon.log",O_CREAT | O_WRONLY | O_APPEND, 0600) < 0){
perror("open");
exit(1);
}
write(fd,buf,len+1);
close(fd);
sleep(10);
}
return 0;
}