linux 守护进程

终端:

在UNIX系统中,用户通过终端登录系统后得到一个Shell进程,这个终端成为Shell进程的控制终端(Controlling Terminal),进程中,控制终端是保存在PCB中的信息,而fork会复制PCB中的信息,因此由Shell进程启动的其它进程的控制终端也是这个终端。默认情况下(没有重定向),每个进程的标准输入、标准输出和标准错误输出都指向控制终端,进程从标准输入读也就是读用户的键盘输入,进程往标准输出或标准错误输出写也就是输出到显示器上。信号中还讲过,在控制终端输入一些特殊的控制键可以给前台进程发信号,例如Ctrl-C表示SIGINT,Ctrl-\表示SIGQUIT。
Alt + Ctrl + F1、F2、F3、F4、F5、F6 字符终端
pts (pseudo terminal slave) 指伪终端
Alt + F7 图形终端
SSH、Telnet… 网络终端

终端的启动流程:

文件与I/O中讲过,每个进程都可以通过一个特殊的设备文件/dev/tty访问它的控制终端。事实上每个终端设备都对应一个不同的设备文件,/dev/tty提供了一个通用的接口,一个进程要访问它的控制终端既可以通过/dev/tty也可以通过该终端设备所对应的设备文件来访问。ttyname函数可以由文件描述符查出对应的文件名,该文件描述符必须指向一个终端设备而不能是任意文件。
简单来说,一个Linux系统启动,大致经历如下的步骤:
init --> fork --> exec --> getty --> 用户输入帐号 --> login --> 输入密码 --> exec --> bash

ttyname函数

由文件描述符查出对应的文件名

char *ttyname(int fd);	

成功:终端名;失败:NULL,并设置errno

#include <unistd.h>
#include <stdio.h>
int main(void)
{
    printf("fd 0: %s\n", ttyname(0));
    printf("fd 1: %s\n", ttyname(1));
    printf("fd 2: %s\n", ttyname(2));
    return 0;
}	

在这里插入图片描述

网络终端:

虚拟终端或串口终端的数目是有限的,虚拟终端(字符控制终端)一般就是/dev/tty1∼/dev/tty6六个,串口终端的数目也不超过串口的数目。然而网络终端或图形终端窗口的数目却是不受限制的,这是通过伪终端(Pseudo TTY)实现的。一套伪终端由一个主设备(PTY Master)和一个从设备(PTY Slave)组成。主设备在概念上相当于键盘和显示器,只不过它不是真正的硬件而是一个内核模块,操作它的也不是用户而是另外一个进程。从设备和上面介绍的/dev/tty1这样的终端设备模块类似,只不过它的底层驱动程序不是访问硬件而是访问主设备。网络终端或图形终端窗口的Shell进程以及它启动的其它进程都会认为自己的控制终端是伪终端从设备,例如/dev/pts/0、/dev/pts/1等。下面以telnet为例说明网络登录和使用伪终端的过程。
在这里插入图片描述

会话

创建会话

创建一个会话需要注意以下注意事项:
1.创建会话的进程不能是一个进程组的组长,否则会出错返回,该进程创建完会话后会变成新会话的首进程(session header)
2.该进程成为一个新进程组的组长进程。
3.需有root权限(ubuntu不需要)
4.新会话丢弃原有的控制终端,该会话没有控制终端
5.建立新会话时,先调用fork, 父进程终止,子进程调用setsid

getsid函数

获取进程所属的会话ID

pid_t getsid(pid_t pid); 

成功:返回调用进程的会话ID;失败:-1,设置errno
pid为0表示察看当前进程session ID
ps ajx命令查看系统中的进程。参数a表示不仅列当前用户的进程,也列出所有其他用户的进程,参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程,参数j表示列出与作业控制相关的信息。
组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程。

setsid函数

创建一个会话,并以自己的ID设置进程组ID,同时也是新会话的ID。

pid_t setsid(void); 

成功:返回调用进程的会话ID;失败:-1,设置errno
调用了setsid函数的进程,既是新会话的首进程(Session Leader),也是新的进程组的组长进程。

守护进程

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

创建守护进程模型
1.创建子进程,父进程退出
所有工作在子进程中进行形式上脱离了控制终端
2.在子进程中创建新会话
setsid()函数
那么,在创建守护进程时为什么要调用setsid函数呢?由于创建守护进程的第一步调用了fork函数来创建子进程,再将父进程退出。由于在调用了fork函数时,子进程全盘拷贝了父进程的会话期、进程组、控制终端等,虽然父进程退出了,但会话、进程组、控制终端等并没有改变,因此,这还不是真正意义上的独立开来,而setsid函数能够使进程完全独立出来,从而摆脱其他进程的控制。
3.改变当前目录为根目录
chdir()函数
这一步也是必要的步骤。使用fork创建的子进程继承了父进程的当前工作目录。由于在进程运行中,当前目录所在的文件系统(如“/mnt/usb”)是不能卸载的,这对以后的使用会造成诸多的麻烦(比如系统由于某种原因要进入单用户模式)。因此,通常的做法是让"/"作为守护进程的当前工作目录,这样就可以避免上述的问题,当然,如有特殊需要,也可以把当前工作目录换成其他的路径。
4.重设文件权限掩码
umask()函数
防止继承的文件创建屏蔽字拒绝某些权限,大大增加守护进程灵活性。在这里,通常的使用方法为umask(0)。
5.关闭文件描述符
同文件权限码一样,用fork函数新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下。
由于守护进程已经与所属的控制终端失去了联系。因此从终端输入的字符不可能达到守护进程,守护进程中用常规方法(如printf)输出的字符也不可能在终端上显示出来。所以,文件描述符为0、1和2 的3个文件(常说的输入、输出和报错)已经失去了存在的价值,也应被关闭。
6.开始执行守护进程的核心工作
7.守护进程退出处理程序模型 (自己在程序里设置信号及对应的捕捉函数即可)

例:自己写一个守护进程

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
void daemonize(void)
{
    pid_t pid;
    
   
    if ((pid = fork()) < 0) 
	{
        perror("fork");
        exit(1);
    } else if (pid > 0) 
        exit(0);//结束父进程
		
    setsid();//子进程成为一个新会话的首进程,失去控制终端
	
    //改变当前工作目录到/目录下.
  
    if (chdir("/") < 0) 
	{
        perror("chdir");
        exit(1);
    }
    //设置umask为0
    umask(0);
	
	
    //重定向0,1,2文件描述符到 /dev/null,因为已经失去控制终端,再操作0,1,2没有意义.
    close(0);
    open("/dev/null", O_RDWR);
    dup2(0, 1);
    dup2(0, 2);
}

int main(void)
{
    daemonize();
	int fd;
	char *buf = "daemond\n";
	int len = strlen(buf);
	if( (fd=open("/home/shenhang/daemon.txt",O_CREAT | O_WRONLY | O_APPEND,0600)) < 0 )
	{
		perror("open");
		exit(1);
	}
	while(1)//在此循环中可以实现守护进程的核心工作
	{
		write(fd,buf,len);
		sleep(5);
	}
	close(fd);

   
}

这里执行的时候,可以使用tail -f /home/shenhang/daemon.txt命令来动态追踪文件的内容,结束进程可以用ps -e | grep daemon来找到进程号,然后kill掉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值