1. 终端 、进程组
1. 什么终端 (tty就是) :所有输入、输出设别的总称 ,
输入, 键盘、鼠标 、摄像头 、麦克风
输出:屏幕、音响、打印机字符终端 : ctrl+alt +f1 - f6
图形终端: alt + f7
网络终端: xshell
虚拟终端 (pty就是) : 虚拟机小窗口 xshell , 可以输入、输出2. 线路规程:
xshell 原理 ssh客户端-- ssh服务器 - 伪终端bash3. 进程组:
父进程fork进程以后, 父进程就是组长, 父进程id 就是进程组id如何把创建的子进程分配到其他进程组中 ?? 可以的
ps aux|grep bash 所有的虚拟终端
操作函数:
getpgrp(void): 获取当前进程的进程组
getpgid(pid_t pid): 获取指定进程的进程组IDsetpgid(pid_d pid,pid_t pgid): 把pid 加入 pgid进程组
子进程 可以加入 bash 组
setpgid(pid_d pid,pid_d pid) 独立一个组,自己pid为组
父进程可以改变子进程
非root用户进程只能改变自己创建的子进程,或有权限操作的进程
代码功能: 在父进程中 自立门户,把自己加入自己的进程组, 把父进程加入bash组
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <signal.h>
int main() {
int i;
pid_t pid=fork();
if(pid < 0){
perror("fork fail");
exit(1);
}else if(pid == 0){
printf("child pid ==%d\n", getpid() );
printf("chidl group=%d\n", getpgid(0)); // 返回组id
printf("child getppid=%d\n",getppid());
// printf("child group=%d\n", getpgrp());
sleep(7); //子进程睡7s ,等待父进程操作 , 父进程把子进程自立门户
printf("change chidl group=%d\n", getpgid(0)); // 返回组id
}else if(pid>0){
sleep(1); //给子进程打印内容
setpgid(pid,pid); // 父进程把自己加入 自己组., 子进程自立门户,成为进程组长,
sleep(13);
printf("\n");
printf("parent id=%d\n", getpid());
printf("bash -- parent group id=%d\n",getppid()); // bash id
printf("parent group id =%d\n", getpgid(0)); // 自己的进程组ID
sleep(5);
// 符进程给进程设置上面, 父进程把自己加入bash组, bash不是root
setpgid(getpid(),getppid());
printf("groupid of parent ischange to= %d\n",getpgid(0));
while(1){ }
}
return 0;
}
执行输出:
2. 守护进程
4.1. 如何创建回话
如何创建回话:
1. 创建会话进程不能是进程组组长,[比如父进程],该进程[子进程]成为新会话的首进程
2. 新会话丢弃原有控制终端,该会话没有控制终端[这种程序不能和用户进程操作,适合在后台运行,守护进程]
3. 建立新会话,调用fork,父进程终止,子进程调用setisid()
4. 建立成功以后 pid=gid=sid
5. 建立会话需要root权限 [ubuntu不需要]
ppid pid gid sid
/**
* 如何创建回话:
1. 创建会话进程不能是进程组组长,[比如父进程],该进程[子进程]成为新会话的首进程
2. 新会话丢弃原有控制终端,该会话没有控制终端[这种程序不能和用户进程操作,适合在后台运行,守护进程]
3. 建立新会话,调用fork,父进程终止,子进程调用setisid()
4. 建立成功以后 pid=gid=sid
5. 建立会话需要root权限 [ubuntu不需要]
ppid pid gid sid
*/
int main00011() {
pid_t pid = fork();
if (pid < 0) {
perror("fork fail");
exit(-1);
} else if (pid == 0) {
printf("child process PID is %d\n", getpid());
printf("group id is %d\n", getpgid(0));
printf("session is %d\n", getsid(0));
sleep(10);
setsid(); // 创建会话
printf("change.......");
printf("child process PID is %d\n", getpid());
printf("group id is %d\n", getpgid(0));
printf("session is %d\n", getsid(0));
} else {
// 父进程死了
}
return 0;
}
4.2.守护进程创建:
1. 独立于控制终端[运行在操作系统后台]并且周期执行某种任务
2. 不受用户登录注销影响,通常以d结尾方式 比如vsftpd[d]
用户程序退出,注销不影响
比如:vsftpd : 启动,等待客户端连接 httpd 、 sshd xinted , mysql就是守护进程自动启动的
比如在./bashrc 启动程序
int main0000013() {
pid_t pid = fork();
if(pid>0){
exit(0); // 父进程终止
}
__pid_t spid=setsid(); //创建新会话
if(spid == -1){
perror("setsid fail");
exit(-1);
}
__pid_t cpid= chdir("/home/denganzhi/linux");
// 改变工作目录
// why? 如果程序在U盘上运行,那么拔掉U盘,程序会崩溃
if(cpid ==-1){
perror("chdir fail");
exit(-1);
}
umask(0022); //改变文件访问权限掩码,避免fork 之前进程修改umask权限,避免跟着原来的掩码走
//0 1 2 进程启动,自动打开, 回话脱离控制终端,0 1 2 无效了
//
close(STDIN_FILENO); // 关闭0号文件描述符, 后面的open 就占据了 0号描述符
// 继承打开文件不会用到,浪费系统资源
// 如果直接关闭,那么文件描述从0开始,不符合习惯
// 可以定向到一个文件,那么还是从3开始文件描述符
int fd=open("/dev/null",O_RDWR);
if(fd == -1){
perror("open error");
exit(-1);
}
dup2(fd,STDOUT_FILENO);
dup2(fd,STDERR_FILENO);
while(1){
}
return 0;
}