-
新会话关联控制终端的方法
-
会话首进程成功打开终端设备 ( 设备打开前处于空闲状态 )
-
关闭标准输入输出和标准错误输出
-
将 stdin 关联到终端设备:STDIN_FILENO -> 0 输入
-
将 stdout 关联到终端设备:STDOUT_FILENO -> 1 输出
-
将stderr 关联到终端设备:STDERR_FILENO -> 2 错误
-
-
-
一些相关推论
-
新会话关联控制终端后,会话中的所有进程生命期与控制终端相关
-
只有会话首进程能够关联控制终端 ( 会话中的其它进程不行 )
-
进程的标准输入输出与标准错误输出可以进行重定向
-
由描述符 0,1,2 决定重定向的目标位置(按顺序打开设备)
-
控制终端与进程的标准输入输出以及标准错误输出无直接关系
-
-
#master.c
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main()
{
char rx = 0;
int master = 0;
int c = 0;
master = posix_openpt(O_RDWR); // gnome-terminal
if( master > 0 )
{
grantpt(master);
unlockpt(master);
printf("Slave: %s\n", ptsname(master));
while( (c = read(master, &rx, 1)) == 1 )
{
if( rx != '\r' )
{
printf("%c", rx);
}
}
close(master);
}
else
{
printf("create pty error...\n");
}
return 0;
}
#session.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int pid = 0;
int i = 0;
if( (pid = fork()) > 0 )
{
printf("parrent = %d, ppid = %d, pgid = %d, sid = %d\n", getpid(), getppid(), getpgrp(), getsid(getpid()));
printf("new: %d\n", pid);
exit(0);
}
else if( pid == 0 )
{
setsid();
sleep(200);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
i += open(argv[1], O_RDONLY); // 0 --> STDIN
i += open(argv[1], O_WRONLY); // 1 --> STDOUT
i += open(argv[1], O_RDWR); // 2 --> STDERR
printf("child = %d, ppid = %d, pgid = %d, sid = %d\n",
getpid(), getppid(), getpgrp(), getsid(getpid()));
printf("i = %d\n", i);
}
else
{
printf("fork error...\n");
}
sleep(240);
return 0;
}
-
什么是守护进程(Daemon)?
-
守护进程是系统中执行任务的后台进程
-
不与任何终端相关联(不接收终端相关的信号)
-
生命周期长,一旦启动,正常情况下不会终止(直到系统退出)
-
Linux大多数服务器使用守护进程实现(守护进程名以后缀d结尾)
-
-
-
守护进程的创建步骤
-
通过 fork()创建新进程,成功后,.父进程退出
-
子进程通过 setsid() 创建新会话
-
子进程通过 fork() 创建孙进程(肯定不是会话首进程)
-
孙进程修改模式 umask(),改变工作目录为"/"
-
关闭标准输入输出和标准错误输出
-
重定向标准输入输出和标准错误输出("/dev/nu")
-
守护进程关键点分析
-
父进程创建子进程是为了创建新会话
-
子进程创建孙进程是为了避免产生控制进程
-
孙进程不是会话首进程,因此不能关联终端
-
重定向操作可以避开奇怪的进程输出行为
-
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char* argv[])
{
int pid = 0;
int i = 0;
if( (pid = fork()) > 0 ) // 1
{
printf("parrent = %d, ppid = %d, pgid = %d, sid = %d\n",
getpid(), getppid(), getpgrp(), getsid(getpid()));
printf("child: %d\n", pid);
exit(0);
}
else if( pid == 0 )
{
setsid(); // 2
if( (pid = fork()) > 0 ) // 3
{
printf("child = %d, ppid = %d, pgid = %d, sid = %d\n",
getpid(), getppid(), getpgrp(), getsid(getpid()));
printf("groundson: %d\n", pid);
exit(0);
}
if( pid == 0 )
{
// 4
umask(0);
chdir("/");
// 5
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 6
i += open("/dev/null", O_RDONLY); // 0 --> STDIN
//放上绝对路径
i += open("/home/ubuntu/TestCode/Linux/d.log", O_WRONLY); // 1 --> STDOUT
i += open("/dev/null", O_RDWR); // 2 --> STDERR
printf("child = %d, ppid = %d, pgid = %d, sid = %d\n",
getpid(), getppid(), getpgrp(), getsid(getpid()));
while( 1 )
{
// do something
printf("i = %d\n", i++);
sleep(1);
fflush(stdout); //强制将缓存区的内容写入到文件
}
}
}
else
{
printf("fork error...\n");
}
return 0;
}
运行结果: