前台和后台
运行简单的打印程序
#include <iostream>
#include <unistd.h>
int main()
{
while (true)
{
std::cout << "hello..." << std::endl;
sleep(1);
}
}
运行之后,会不断往屏幕上打印hello…,输入命令没有反应
切换到后台运行后
还是不断往屏幕打印,但可以正常接收命令了,说明标准输出并不能区分前台和后台
前台和后台程序的区分就是哪个拥有标准输入,一般标准输入只有一个
当有用户登录的时候,就会形成一个会话,会话中有1个前台进程和n个后台进程。当上面的程序运行的时候,bash这个接收命令输入的前台进程会自动放到后台,test程序结束后又切换回来
命令操作
运行一个后台任务时打印的数字叫后台任务号,后面的是pid
查看后台任务
多运行几个test,重定向到文件不影响屏幕
jobs //查看后台任务
前后台切换
想把一个任务切到前台或后台
fg 任务号 //提到前台
暂停
提到前台后就会拥有标准输入,让任务进入暂停状态,发送SIGSTOP信号,bash会切回前台
crtl+z 任务暂停
恢复
恢复暂停的任务
bg 任务号
当前值作业列表中的+号,-号称为当前值标志。+号说明改作业位当前默认作业,-号说明当前默认作业完成后将替代当前默认作业。
任务
后台开启三个sleep进程,运行一个上面的程序对比
sleep 1000 | sleep 2000 | sleep 3000 &
PGID:进程组id
SID:会话session id
TPGID:终端进程组id
TTY:终端
单独启动的test程序PID和PGID是一样的,自成一组,同时启动的sleep程序PID都不一样,PGID是第一个sleep程序,进程组是一样的,是同一组。这几个都属于同一个会话和终端
一个任务是一个具体的行为,比如输出一串信息等,任务可以交由一个进程完成或者一组进程完成
SID7702就是bash,每次登录创建一个bash,用bash的id去创建一个会话
守护进程
概念
开启四个后台进程,再关闭会话重新打开
这些进程会随着会话的关闭改变,会话id会别保留下来,终端变成了未知,父进程被os领养,成了1号
这些受到了用户登录和退出影响,如果不想受到,就得守护进程化
让bash内的一个进程自成会话, bash登录关闭就不会影响它
函数
让进程成为会话,要设置的进程不能是组长,所以用fork
修改tcp程序
编写daemon守护功能
1.忽视影响的信号
2.创建子进程,独立会话
3.输入输出等重定向到垃圾桶文件
#include <string>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
const std::string nullfile = "/dev/null";
void daemon(const std::string cwd = "")
{
//1.忽略其他信号
signal(SIGCLD, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
// 2.创建子进程,变成独立绘画
if (fork() > 0)
exit(0);
setsid();
if (!cwd.empty())
chdir(cwd.c_str());
//3.输出输入修改,/dev/null 垃圾桶
int fd = open(nullfile.c_str(), O_RDWR);
if (fd > 0)
{
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
}
}
使用功能
在run功能开始时调用
运行服务端,查看效果
这时服务就是一直开启的,关闭会话后照样可以连接
传入目录参数也可以修改工作目录
可以在开始的时候将日志设置到文件,这样将工作目录放到系统可执行路径,日志放在系统环境路径,就可以是系统内的一个程序