013会话和守护进程

会话和守护进程

1. 进程组和会话概念

1.1 进程组

进程组概念:

进程组,也称之为作业。BSD于1980年前后向Unix中增加的一个新特性。代表一个或多个进程的集合。每个进程都属于一个进程组。在waitpid和kill函数的参数中都曾使用过。操作系统设计的进程组的概念,是为了简化对多个进程的管理

当父进程,创建子进程的时候,默认子进程与父进程属于同一个进程组。进程组ID = 第一个进程ID(组长进程)。所以,组长进程标识,其进程组ID = 其进程ID

kill 命令杀死整个进程组:
kill -9 -进程组ID    //杀死整个进程组内的进程全部杀死
进程组的生存期:

组长进程可以创建一个进程组,创建该进程组中的进程,然后终止。只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关。
进程组的生存期,进程组创建到最后一个进程离开(终止或转移到另一个进程组)
一个进程可以为自己或子进程设置进程组

1.2 会话

会话:

就是进程组的集合

在这里插入图片描述

创建会话:

创建一个会话需要注意以下6点:

  1. 调用进程不能是进程组组长,该进程变成新会话的首进程
  2. 该进程成为一个新进程组的组长进程
  3. 需要root权限 (Ubuntu不需要)
  4. 新会话丢弃原有的控制终端,该会话没有控制终端
  5. 如果该进程调用的是组长进程,则出错返回
  6. 建立新会话时,先调用fork,父进程终止,子进程调用setsid()
ps ajx 查看当前进程会话ID
ps ajx 查看系统中的进程
a:列出所有用户的进程
j:列出与作业控制相关的信息
x:显示 有控制终端的进程 和 没有控制终端的进程

注意:组长进程不能成为新会话的首进程,新会话的首进程必定回成为组长进程

getsid() 获取进程所属的会话ID
#include<sys/types.h>
#include<unistd.h>

pid_t getsid(pid_t pid);

返回值:
成功:返回调用进程的会话ID
失败:-1,设置errno

pid = 0:表示查看当前进程会话ID

setsid() 创建会话
#include<sys/types.h>
#include<unistd.h>

pid_t setsid(void);

返回值:
成功:返回调用进程的会话ID
失败:-1,设置errno

demo 创建会话
  1. fork 创建子进程,父进程退出
  2. 打印子进程信息
  3. setsid 创建会话
  4. 打印子进程信息
/* session.c */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc, char * argv [ ])
{
	pid_t pid;


	if ((pid = fork()) < 0)
	{
		perror("fork error\n");
		exit(1);
	}
	else if(pid == 0)
	{
		printf("child process PID is %d\n", getpid());
		printf("Group ID of child is %d\n",getpgid(0));
		printf("Session ID of child is %d\n", getsid(0));

		sleep(10);
		setsid();	// 子进程非组长进程,故其成为新会话的首进程(组长进程)

		printf("changed:\n");

		printf("child process PID is %d\n", getpid());
		printf("Group ID of child is %d\n",getpgid(0));
		printf("Session ID of child is %d\n", getsid(0));

		sleep(20);
		exit(0);
	}

	return 0;
}

在这里插入图片描述

2. 守护进程

2.1 守护进程的概念

Daemon(精灵)进程,是Linux中的后台服务进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以d结尾的名字。
Linux后台的一些系统服务进程,没有控制终端,不能直接和用户交互。不受用户登录、注销的影响,一直在运行着,他们都是守护进程。如:预读入缓输出机制的实现;ftp服务器;nfs服务器等。
创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。

2.2 创建守护进程模型

  1. 创建子进程,父进程退出
       所有工作在子进程中进行形式上脱离了控制终端
  2. 在子进程中创建新会话
       setsid() 函数
       使子进程完全独立出来,脱离控制
  3. 根据需要,改变当前目录位置(防止目录被卸载)
       chdir() 函数
       防止占用可卸载的文件系统
       也可以换成其他路径
  4. 根据需要,重设文件权限掩码
       umask 函数
       防止继承的文件创建屏蔽字拒绝某些权限
       增加守护进程的灵活性
  5. 根据需要,关闭/重定向 文件描述符 // 123 或者重定向到 /dev/null
        继承的打开文件不会用到,浪费系统资源,无法卸载
  6. 开始执行守护进程核心工作守护进程退出处理程序模型

修改文件路径

man 2 chdir    //change working directory

#include<unistd.h>

int chdir(const char *path);

重设文件掩码

man 2 umask	// set file mode creation mask

#include<sys/types.h>
#include<sys/stat.h>

mode_t umask(mode_t mask); 	// 一直成功,返回原来mask

2.3 demo 守护进程

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<signal.h>
#include<fcntl.h>
#include<sys/stat.h>

void sys_error(const char * str)
{
	perror(str);
	exit(1);
}

int main(int argc, char * argv [ ])
{
	pid_t pid;
	int ret,fd;

	pid = fork();
	if(pid > 0)
	{
		exit(0);	// 父进程终止
	}

	pid = setsid();	//创建新会话
	if (pid == -1)
		sys_error("setsid error\n");

	ret = chdir("/home/libai");		// 改变工作目录位置
	if(ret == -1)
		sys_error("chdir error\n");

	umask(0022);			// 改变文件访问权限掩码

	close(STDIN_FILENO);	// 关闭文件描述符0
	fd = open("/dev/null" , O_RDWR);	// fd-->/dev/null
	if(fd == -1)
		sys_error("open error\n");

	dup2(fd, STDOUT_FILENO);	// 重定向 stdout 和 stderr
	dup2(fd, STDERR_FILENO);

	while(1);		// 模拟守护进程逻辑
	

	return 0;
}

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值