Linux 终端-进程组-会话-守护进程
- 终端
1>ctrl+alt+(1-6)文字终端,7是图形终端
文字终端(bash)的启动流程
- 网络终端
- 进程组(作业)
1>进程组ID=第一个进程ID(组长ID)
2>kill -SIGKILL -进程组ID(负的) //杀死进程组内的全部进程
3>进程组生命周期:进程组创建到最后一个进程结束(注意:组长进程结束,该进程并不会结束)
4>进程组操作函数
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
/*******************************************************
*函数1:getpgrp()
*头文件:#include <unistd.h>
*格式:pid_t getpgrp(void);//无形参
*作用:获取当前进程组ID
*返回值:The POSIX.1 getpgrp() always returns the PGID of the caller.
*********************************************************
*函数2:getpgid()
*头文件:#include <unistd.h>
*格式:pid_t getpgid(pid_t pid);//有参数:参数传0时,相当于getpgrp();
*作用:获取指定进程组ID
*返回值:getpgid(), and the BSD-specific getpgrp() return a process group on success. On error, -1 is returned, and errno is set appropriately.
*********************************************************
*函数3:setpgid()
*头文件:#include <unistd.h>
*格式: int setpgid(pid_t pid, pid_t pgid);//参数1:要改变默认所属进程组的进程;参数2:要加入或则要创建的进程.
*作用:将参数1进程加入到参数2进程组中,通常是改变默认所属进程组,达到加入其他进程组或则创建一个新的进程组
*返回值:成功-0;失败--1;
*注意:1>如果子进程要创建新的进程组需要在fork()函数与execxx()函数之间(因为execxx()函数无返回值)
* 2>非root进程只能改变自己创建的子进程和有权操作的进程.
* 3>getpid();getppid();
*********************************************************/
int main()
{
pid_t pid =fork();
if(pid==-1)
{
perror("fork");
exit(1);
}
if(pid>0)
{
printf("parent process group ID:%d\n",getpgid(0));
sleep(1);
setpgid(pid,pid); //改变子进程进程组ID为自己的ID
sleep(3);
wait(NULL);
}
else{
printf("child process ID:%d\n",getpid());
printf("child process group ID:%d\n",getpgrp());
sleep(2);
printf("child process new group ID:%d\n",getpgrp());
}
return 0;
}
运行结果:
- 会话(session)
1>进程组合在一起叫进程组,进程组组合在一起叫会话;
组长进程不能成为新会话首进程,但会话首进程移动成为组长进程.
2>函数
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
/*******************************************************
*函数1:getsid()
*头文件:#include <unistd.h>
*格式:pid_t getsid(pid_t pid);//pid=0:获取当前进程的会话ID,!=0:获取指定进程的会话ID;
*作用:获取当前进程所属的会话ID
*返回值:成功-会话ID,失败--1;
*********************************************************
*函数2:setsid()
*头文件:#include <unistd.h>
*格式:pid_t setsid(void);
*作用:创建新的会话,并以自己ID为新的会话ID和组ID;
*返回值:成功-新的会话ID,失败--1;
*********************************************************/
int main()
{
pid_t pid =fork();
if(pid==-1)
{
perror("fork");
exit(1);
}
//不能用父进程创建会话
if(pid==0)
{
//打印当前的各个ID
printf("child process session ID:%d\n",getsid(0));//获取当前进程的会话id
printf("child process ID:%d\n",getpid());
printf("child process group ID:%d\n",getpgid(0));//获取当前进程的组id
if(setsid()==-1)//设置新的会话ID
{
perror("setsid error");
exit(1);//exit(0)正常退出
}
printf("********************child process session ID changed*******************\n");
//打印新的的各个ID
printf("child process session ID:%d\n",getsid(0));
printf("child process ID:%d\n",getpid());
printf("child process group ID:%d\n",getpgid(0));
}
return 0;
}
运行结果:
- 守护进程(daemon)
1>后台服务进程,一般以d结尾:eg:vsftpd httpd sshd xinetd等.
2>没有终端,不能直接交互(也就不需要文件描述符0\1\2)不受用户登录\注销的影响一直在运行.
3>创建守护进程(关键是创建会话)
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t pid;
//1步创建子进程
if((pid=fork())==-1)
{
perror("fork error");
exit(1);
}
if(pid>0)
return 0;
//子进程
else{
//2步:创建新会话
setsid();
//3步:改变进程的工作目录
if(chdir("/home/khy/"))//要检查返回值,此函数容易出错
{
perror("chdir error");
exit(1);
}
//4步:指定文件掩码
umask(0002);//文件创建的权限一般为775,所以掩码取002,第一个零表示八进制.
//5步:关闭文件描述符0/1/2;或则重定向到/dev/null下面(收垃圾的)
close(STDIN_FILENO);
open("/dev/null");//此时文件描述符为0,就小原则.
dup2(0,STDOUT_FILENO);
dup2(0,STDERR_FILENO);
//6步:守护进程逻辑,一直执行,用while()实现.
while(1)
{
//因为守护进程没有终端,且不会应为用户登录注销影响(开机会影响),
//所以想要开机就启动就要把它加入.bashrc里面或则init里面,开机启动.
//7步:退出
//这里一般要捕捉一个信号,来杀死自己.
}
}
return 0;
}