Assignment 2 Linux守护进程

上传人:飞*** 文档编号:4828401 上传时间:2017-08-26 格式:DOCX 页数:10 大小:50.35KB
返回 下载 相关 举报
Assignment 2 Linux守护进程_第1页
第1页 / 共10页
Assignment 2 Linux守护进程_第2页
第2页 / 共10页
Assignment 2 Linux守护进程_第3页
第3页 / 共10页
Assignment 2 Linux守护进程_第4页
第4页 / 共10页
Assignment 2 Linux守护进程_第5页
第5页 / 共10页
点击查看更多>>
资源描述

《Assignment 2 Linux守护进程》由会员分享,可在线阅读,更多相关《Assignment 2 Linux守护进程(10页珍藏版)》请在金锄头文库上搜索。

1、Assignment 2 Linux Daemon请参考如下的“Linux 守护进程”一文,创建一个守护进程,在该进程中创建日志文件/tmp/cpu.log,并每隔 10秒钟记录 CPU 的利用率。说明:1、要求实现为一个完整的可执行 C 程序,在服务器中测试你的实现结果;2、请将你实现的源代码和结果的拷屏截取,打包作为结果提交给本班的辅导老师;3、出错处理部分尽量完成,但不做强制要求。Linux 守护进程1守护进程概述守护进程,也就是通常所说的 daemon 进程,是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

2、守护进程常常在系统引导载入时启动,在系统关闭时终止。Linux 有很多系统服务,大多数服务都是通过守护进程实现的。同时,守护进程还能完成许多系统任务,例如,作业规划进程 crond、打印进程 lqd 等(这里的结尾字母 d 就是 daemon 的意思)。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。但是守护进程却能够突破这种限制,它从被执行开始运转,直到接收到某种信号或者整个系统关闭时才会退出。如果想让某个进程不因为用户、终端或者其他的变化而受到影响,那

3、么就必须把这个进程变成一个守护进程。可见,守护进程是非常重要的。2编写守护进程编写守护进程看似复杂,但实际上也是遵循一个特定的流程,只要将此流程掌握了,就能很方便地编写出自己的守护进程。下面就分 4 个步骤来讲解怎样创建一个简单的守护进程。在讲解的同时,会配合介绍与创建守护进程相关的几个系统函数,希望读者能很好地掌握。(1)创建子进程,父进程退出。这是编写守护进程的第一步。由于守护进程是脱离控制终端的,因此,完成第一步后就会在 shell 终端造成一种程序已经运行完毕的假象,之后的所有工作都在子进程中完成,而用户在 shell 终端则可以执行其他的命令,从而在形式上做到与控制终端的脱离。到这里

4、,有心的读者可能会问,父进程创建了子进程后退出,此时该子进程不就没有父进程了吗?守护进程中确实会出现这么一个有趣的现象:由于父进程已经先于子进程退出,就会造成子进程没有父进程,从而变成一个孤儿进程。在 Linux 中,每当系统发现一个孤儿进程时,就会自动由 1 号进程(也就是 init 进程)收养它,这样,原先的子进程就会变成 init 进程的子进程。其关键代码如下: pid = fork();if (pid 0)exit(0); /* 父进程退出 */(2)在子进程中创建新会话。这个步骤是创建守护进程最重要的一步,虽然实现非常简单,但意义却非常重大。在这里使用的是系统函数 setsid(),

5、在具体介绍 setsid()之前,读者首先要了解两个概念:进程组和会话期。 进程组。进程组是一个或多个进程的集合。进程组由进程组 ID 来唯一标识。除了进程号(PID )之外,进程组 ID 也是一个进程的必备属性。每个进程组都有一个组长进程,其组长进程的进程号等于进程组 ID,且该进程 ID 不会因组长进程的退出而受到影响。 会话期。会话组是一个或多个进程组的集合。通常,一个会话开始于用户登录,终止于用户退出,在此期间该用户运行的所有进程都属于这个会话期。进程组和会话期之间的关系如图 1 所示。图 1 进程组和会话期之间的关系接下来就可以具体介绍 setsid()的相关内容。 setsid()

6、函数的作用。setsid()函数用于创建一个新的会话组,并担任该会话组的组长。调用 setsid()有以下 3 个作用: 让进程摆脱原会话的控制。 让进程摆脱原进程组的控制。 让进程摆脱原控制终端的控制。那么,在创建守护进程时为什么要调用 setsid()函数呢?回忆一下创建守护进程的第一步,在那里调用了 fork()函数来创建子进程再令父进程退出。由于在调用 fork()函数时,子进程全盘复制了父进程的会话期、进程组和控制终端等,虽然父进程退出了,但原先的会话期、进程组和控制终端等并没有改变,因此,还不是真正意义上的独立。而 setsid()函数能够使进程完全独立出来,从而脱离所有其他进程的

7、控制。 setsid()函数格式。表 1 列出了 setsid()函数的语法要点。表 1 setsid()函数语法要点所需头文件 #include #include 函数原型 pid_t setsid(void)函数返回值 成功:该进程组 ID出错:-1(3)改变当前目录为根目录。这一步也是必要的步骤。使用 fork()创建的子进程继承了父进程的当前工作目录。由于在进程运行过程中,当前目录所在的文件系统(如“/mnt/usb”等)是不能卸载的,这对以后的使用会造成诸多的麻烦(如系统由于某种原因要进入单用户模式)。因此,通常的做法是让“/”作为守护进程的当前工作目录,这样就可以避免上述问题。当然

8、,如有特殊需要,也可以把当前工作目录换成其他的路径,如/tmp。改变工作目录的常见函数是 chdir()。(4)重设文件权限掩码。文件权限掩码是指屏蔽掉文件权限中的对应位。例如,有一个文件权限掩码是 050,它就屏蔽了文件组拥有者的可读与可执行权限。由于使用 fork()函数新建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带来了诸多的麻烦。因此,把文件权限掩码设置为 0,可以大大增强该守护进程的灵活性。设置文件权限掩码的函数是 umask()。在这里,通常的使用方法为 umask(0)。(5)关闭文件描述符。同文件权限掩码一样,用 fork()函数新建的子进程会从父进程那里继承一

9、些已经打开的文件。这些被打开的文件可能永远不会被守护进程读或写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法被卸载。在上面的第(2)步之后,守护进程已经与所属的控制终端失去了联系,因此,从终端输入的字符不可能达到守护进程,守护进程中用常规方法(如 printf())输出的字符也不可能在终端上显示出来。所以,文件描述符为 0、 1和 2 的 3 个文件(常说的输入、输出和报错这 3 个文件)已经失去了存在的价值,也应被关闭。通常按如下方式关闭文件描述符:for(i = 0; i #include#include#include#include#include#includeint ma

10、in()pid_t pid;int i, fd;char *buf = This is a Daemonn;pid = fork(); /* 第一步 */if (pid 0)exit(0); /* 父进程退出 */setsid(); /* 第二步 */chdir(/); /* 第三步 */umask(0); /* 第四步 */for(i = 0; i 函数原型 void openlog (char *ident, int option , int facility)ident 要向每个消息加入的字符串,通常为程序的名称LOG_CONS:如果消息无法送到系统日志服务,则直接输出到系统控制终端LO

11、G_NDELAY:立即打开系统日志服务的链接。在正常情况下,直接发送到第一条消息时才打开链接LOG_PERROR:将消息也同时送到 stderr 上optionLOG_PID:在每条消息中包含进程的 PIDLOG_AUTHPRIV:安全/授权信息LOG_CRON:时间守护进程(cron 及 at)LOG_DAEMON:其他系统守护进程LOG_KERN:内核信息LOG_LOCAL07:保留LOG_LPR:行打印机子系统函数传入值facility:指定程序发送的消息类型LOG_MAIL:邮件子系统LOG_NEWS:新闻子系统LOG_SYSLOG:syslogd 内部所产生的信息LOG_USER:一

12、般使用者等级信息LOG_UUCP:UUCP 子系统表 3 列出了 syslog()函数的语法要点。表 3 syslog()函数语法要点所需头文件 #include 函数原型 void syslog(int priority, char *format, .)LOG_EMERG:系统无法使用LOG_ALERT:需要立即采取措施LOG_CRIT:有重要情况发生函数传入值priority:指定消息的重要性 LOG_ERR:有错误发生LOG_WARNING:有警告发生LOG_NOTICE:正常情况,但也是重要情况LOG_INFO:信息消息priority:指定消息的重要性 LOG_DEBUG:调试信息

13、函数传入值format 以字符串指针的形式表示输出的格式,类似于 printf 中的格式表 3.4 列出了 closelog()函数的语法要点。表 3.4 closelog()函数语法要点所需头文件 #include 函数原型 void closelog(void)3)使用实例这里将上一个示例程序用 syslog 服务进行重写,其中有区别的地方用加粗的字体表示,源代码如下:/* syslog_daemon.c 利用 syslog 服务的守护进程实例 */#include #include #include #include #include #include #include #include

14、 int main()pid_t pid, sid;int i, fd;char *buf = This is a Daemonn;pid = fork(); /* 第一步 */if (pid 0)exit(0); /* 父进程退出 */* 打开系统日志服务, openlog */openlog(daemon_syslog, LOG_PID, LOG_DAEMON); if (sid = setsid() 0) /* 第二步 */syslog(LOG_ERR, %sn, setsid);exit(1);if (sid = chdir(/) 0) /* 第三步 */syslog(LOG_ERR,

15、 %sn, chdir);exit(1);umask(0); /* 第四步 */for(i = 0; i getdtablesize(); i+) /* 第五步 */close(i);/* 这时创建完守护进程,以下开始正式进入守护进程工作 */while(1)if (fd = open(/tmp/daemon.log, O_CREAT|O_WRONLY|O_APPEND, 0600) 0)syslog(LOG_ERR, open);exit(1);write(fd, buf, strlen(buf) + 1);close(fd);sleep(10);closelog();exit(0);读者可以尝试用普通用户的身份执行此程序。由于这里的 open()函数必须具有 root 权限,因此,syslog 会将错误信息写入到系统日志文件(如“/var/log/messages”)中,结果如下:Jan 30 18:20:08 localhost daemon_syslog612: open

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 研究报告 > 综合/其它

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号