linux+基本++守护进程,Linux守护进程基础

1 守护进程中涉及到的基本概念

1.1进程组

1.1.1 进程组基本概念

进程组是一个或多个进程的集合,可以接收来自同一个终端的各种信号。每运行一个程序或是命令都将产生一个进程组。

每个进程属于一个进程组,而每个进程组都存在一个领头进程(或是叫组长进程),一般进程组的第一个进程是领头进程。领头进程可以创建一个进程组、创建该组中的进程。领头进程fork出的子进程也将在该进程组中,一旦子进程执行exec等退出函数就不再属于该进程组。

进程组的生命周期:从创建开始到最后一个进程离开为止成为进程组的生命周期。组中最后一个进程的离开可以是终止,或加入其他进程。进程组的生命周期与组长进程是否终止无关,只要有一个进程存在,进程组的生命周期就未结束。

1.1.2 相关命令

1、查看所有进程组pid(即领头进程的pid):ps –A –o pgrp= | sort |uniq

2、查看某个进程的进程组pid:ps –C 进程名 –o pgrp=

3、根据进程名获得进程pid:pidof 进程名

4、根据进程pid获得进程名:ps –aux |grep 进程pid

5、获取某个进程的具体信息:ps –ef |grep 进程名或进程pid

1.1.3 相关函数

#include

pid_t getpgrp();    //获取进程组pid,即进组中的领头进程的pid,相当于调用getpgid(0)

pid_t getpid();     //获取当前进程pid

pid_t getppid();    //获取当前进程的父pid

pid_t getpgid();    //返回指定进程的进程组pid

int setpgid(pid_t pid, pid_t pgid); /*将pid进程的进程组id设置为pgid,如果两个参数相等,

*则pid指定的进程变成进程组组长。如果pid是0,则进程

*组id为pgid,如果pgid是0,则进程组id为pid。*/

int setpgrp();  //将当前进程所属的进程组的pid设置为当前进程的pid,相当于setpgid(0, 0)

1.2会话

1.2.1 会话基本概念

一次登录形成一个会话,一个会话可包括多个进程组(一个前台进程组和多个后台进程组),但只能有一个前台进程组。

1.2.2 相关函数

#include

pid_t setsid();

当调用该函数的进程不是进程组的领头进程时,该函数才能建立新的会话。函数调用成功后,调用进程成为新会话的领头进程和新进程的领头进程,同时进程失去控制终端。

1.3控制终端

进程组中有领头进程,类似地,会话中也对应有领头进程。会话的领头进程打开一个终端之后,该终端就成为会话的控制终端,与控制终端建立连接的会话的领头进程成为控制进程(session leader)。一个会话只能有一个控制终端,同时一个控制终端只能一个会话。         产生在控制端上的输入和信号(比如按下ctrl+c就会产生SIGINT信号)将发送给会话的前台进程组中的所有进程。

2守护进程及其特性

1、守护进程最重要的特性是后台运行;

2、守护进程必须与其运行前的环境脱离开来。这些环境包括未关闭的文件描述符,控制终端,会话和进程组,工作目录等,这些环境通常是从执行它的父进程(特别是Shell)中继承下来的。

3、守护进程可以在Linux系统启动时从脚本/etc/rc.d中启动,可以由作业规划进程crond启动,还可以由用户终端(通常是Shell)执行。

3 守护进程编程

针对守护进程的特性可以将普通进程改造为守护进程。

3.1后台运行特性

让daemon在子进程中运行。

if( pid=fork() )

{

exit(0);  //父进程结束,子进程继续

}

3.2脱离环境

3.2.1脱离进程组、登录会话和控制终端

进程组、登录会话和控制终端通常都是从父进程继承下来的,为了不受它们的影响,控制终端必须将其摆脱。具体方法是调用setsid函数。

通过if( pid=fork() ){exit(0);}将产生了子进程,能保证调用setsid的进程不是进程组中的领头进程。当setsid调用成功后,该子进程成为新会话中的领头进程和进程组的领头进程,并脱离了原来的会话、进程组和控制终端。

3.2.2禁止进程打开控制终端

if( pid=fork() )

{

exit(0);  //该子进程结束,又产生子进程

}

结束该子进程,产生新的子进程,此时的新子进程不是会话领头进程,所以不能打开控制终端。通过这种方式就能禁止进程打开控制终端。

3.2.3脱离打开的文件描述符

进程从其父进程继承了打开的文件描述符。如不关闭,将会造成系统资源的浪费,同时,造成进程所在的文件系统无法卸载以及引起其他无法预料的错误。

max_fd = sysconf(_SC_OPEN_MAX);

for(i = 0; i < max_fd; i++)

{

close(i);

}

3.2.4脱离当前工作目录

进程活动时,其工作目录所在的文件系统不能卸载,一般需要将工作目录切换到根目录。对于需要运行日志的进程将工作目录改变到特定的目录。

chdir(“/”);

3.2.5重设文件的权限掩码

进程从其父进程继承的文件的权限掩码,可能会修改守护进程所创建的文件权限,需要将掩码清楚。

umask(0);

3.2.6处理SIGCHLD信号

处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程没有等待(没有调用wait或waitpid)子进程的结束,子进程将成为僵尸进程(Zombie Process)从而占用系统资源。而如果父进程等待子进程结束,又将增加父进程的负担,影响服务器进程的并发性能。在Linux可以将SIGCHLD设置为SIG_IGN,这样内核在子进程结束时不会产生僵尸进程。

signal(SIGCHLD, SIG_IGN);  //屏蔽SIGCHLD信号

这是常用于并发服务器提升性能的一个技巧。当服务器进程没有调用wait去清理子进程而产生僵尸子进程时,如果屏蔽了SIGCHLD信号,内核会把僵尸子进程转交给init进程处理。

4 守护进程示例

#include 

#include 

#include 

#include 

#include 

#include 

void init_daemon()

{

int pid;

int i;

int max_fd;

if(pid = fork())

{

exit(0); //父进程结束,子进程继续

}

else if(pid 

{

exit(1); //fork失败

}

setsid();

if(pid = fork())

{

exit(0); //该子进程结束,又产生新子进程

}

else if(pid 

{

exit(1); //fork错误,退出

}

/* 关闭打开的文件描述符*/

max_fd = sysconf(_SC_OPEN_MAX);

for(i = 0; i 

{

close(i);

}

/* 切换工作目录 */

chdir("/tmp");

/* 重设文件创建掩码 */

umask(0);

return;

}

int main()

{

FILE *fp = NULL;

signal(SIGCHLD, SIG_IGN);

init_daemon();

while(1)

{

sleep(1);

if((fp = fopen("/mnt/hgfs/Share/unix/test.log", "a")) != NULL)

{

fprintf(fp, "%s\n", "test message");

fclose(fp);

}

}

return 0;

}

编译:gcc –o daemon daemon.c

运行:./daemon

查看守护进程:ps –ef |grep daemon

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值