Linux多任务编程之七:Linux守护进程及其基础实验(转)
来源:CSDN 作者:王文松 转自Linux公社
------------------------------------------------------------------------------------------------
守护进程概述
守护进程,又叫daemon进程(不知怎的,我突然想起来吸血鬼日记中的达蒙了,很好看的美剧),是Linux中的后台服务进程。 他是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或者等待处理某些发生的事件。守护进程常常在系统引导载入时启动,在系统关闭时终 止。Linux有很多系统哦服务,大多数服务都是通过守护进程实现的。同时,守护进程还能完成许多系统任务,例如,作业规划进程cronf、打印进程 lqd等(这里的结尾字母 d 就是 daemon的意思)。
在Linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端称为这些进程的控制终端, 当控制终端关闭时,相应的进程都会自动关闭。但是守护进程却能够突破这种限制,它从被执行开始运转,直到接收到某种信号或者整个系统关闭时才退出。如果想 让某个进程不因为用户、终端或者其它的变化而受到影响,那么就必须把这个进程变成一个守护进程。可见,守护进程是非常重要的。
编写守护进程步骤
编写守护进程遵循一个特定的流程,下面就说一下守护进程的创建步骤。
1、创建子进程,父进程退出。
这是编写守护进程的第一步。由于守护进程是脱离控制终端的,因此,完成第一步后就会在shell终端造成一种程序已经运行完毕的假象,之后的所有工作都在子进程中完成,而用户在shell终端则可以执行其他的命令,从而在形式上做到与控制终端的脱离。
但是,父进程创建了子进程后退出,此时该子进程不就没有父进程了吗?守护进程中确实会出现这么一个有趣的现象:由于父进程已经先于子进程退出,就会 造成子进程没有父进程,从而变成一个孤儿进程。在Linux中,每当系统发现一个孤儿进程时,就会自动由1号进程(也就是 init 进程)收养它,这样原先的子进程就会变成 init 进程的子进程。其关键代码如下;
2、在子进程中创建新会话
这个步骤是创建守护进程最重要的一步,虽然实现非常简单,但意义却非常重大。在这里使用的是系统函数 setsid(),在具体介绍 setsid()之前,先了解以下两个概念:进程组和会话期。
● 进程组。进程组是一个或多个进程的集合。进程组由进程组ID来唯一标识。除了进程号PID之外,进程组ID也是一个进程的必备属性。每隔进程组都有一个组 长进程,其组长进程的进程号PID等于进程组ID,且该进程组ID不会因为组长进程的退出而受到影响。(组长没了,再找个组员来担任组长呗)
● 会话期。会话组是一个或多个进程组的集合。通常,一个会话开始于用户登录,终止于用户退出,在此期间该用户运行的所有进程都属于这个会话期。进程组和会话期之间的关系如图1所示:
接下来具体介绍 setsid()的相关内容。
① setsid()函数的作用。setsid()函数用于创建一个新的会话组,并让执行此函数的进程担任该会话组的组长。调用setsid()有以下3个作用:
● 让进程摆脱原会话的控制
● 让进程摆脱原进程组的控制
● 让进程摆脱原控制终端的控制
那么,回过头来想想,在创建守护进程时为什么要调用 setsid()函数呢?是这样的,在创建守护进程的第一步中,调用了fork()函数创建子进程再令父进程退出。由于在调用 fork()函数时,子进程全盘复制了父进程的会话期、进程组和控制终端等,虽然父进程退出了,但原先的会话期、进程组和控制终端等并没有改变,因此,还 不是真正意义上的独立。而setsid()函数能够使进程完全独立出来,从而脱离所有其他进程的控制。
② setsid函数格式
3、改变当前目录为根目录
这一步也是必要的步骤。使用fork()创建的子进程继承了父进程的当前工作目录。由于在进程运行过程中,当前目录所在的文件系统(如“/mnt /usb”等)是不能卸载的,这对以后的使用会造成诸多的麻烦(如系统由于某种原因需要进入单用户模式)。因此,通常的做法是让“/”作为守护进程的当前 工作目录,这样就可以避免上述问题。当然,如有特殊需要,也可以把当前工作目录换成其他的路径,如/tmp。改变工作目录的常见函数是chdir()。
4、重设文件权限掩码
文件权限掩码是指屏蔽掉文件权限中的对应位。例如,有一个文件权限掩码是050,它就屏蔽了文件组拥有者的可读与可执行权限。由于使用fork() 函数新建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带来了诸多的麻烦。因此,把文件权限掩码设置为0,可以大大增强该守护进程的灵活 性。设置文件权限掩码的函数是umask()。通常的使用方法为umask(0)。
5、关闭文件描述符
同文件权限掩码一样,用fork()函数新建的子进程会从父进程那里继承一些已经打开的文件。这些被打开的文件可能永远不会被守护进程读或写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法被卸载。
事实上,在上面的第2步之后,守护进程已经与所属的控制终端失去了联系,因此,从终端输入的字符不可能达到守护进程,守护进程中用常规方法(如 printf())输出的字符也不可能在终端上显示出来。所以文件描述符为0,1和2的3个文件(常说的输入/输出和报错这3个文件)已经失去了存在的价 值,也应该被关闭。通常了,按如下方式关闭文件描述符:
有关getdtables()的作用请看博客:
到这里,一个简单的守护进程就建立起来了。创建守护进程的流程图如图所示:
基础实验
本实验按照以上的创建流程建立了一个守护进程,然后让守护进程每隔10s向日志文件/home/song/tmp/daemon.log 写入一句话。程序代码如下,我也上传到网站,点此下载
我们先看一下 /tmp文件夹下是没有daemon.log的
下载文件后,使用命令编译:gcc dameon.c -o daemon
然后执行命令: ./daemon 你可以看到此时没有看到有什么变化
使用命令:ps -ef|grep ./daemon 利用ps中的关键字来查看系统当前正在运行的进程中,有没有咱们的daemon进程
可以看到咱们的守护进程已经在运行了,再来看看/tmp目录下的内容
可以看到,已经有daemon.log日志文件了。
然后使用命令:tail -f /tmp/daemonl.log ,可以看到该程序每隔10s就会在对应的文件中输入相关的内容
到这里,这个实验就已经结束了,通过前边使用命令:ps -ef|grep ./daemon可以看到咱们这个进程的进程号是3346,现在使用命令:kill -9 3346将这个进程杀死,同时也把/tmp中的daemon.log文件页删除,方便咱们下边的实验。
守护进程的出错处理
在编写守护进程的具体调试过程中会发现,由于守护进程完全脱离了控制终端,因此,不能像其他普通进程一样,将错误信息输出到控制终端来通知程序员, 即使使用gdb也无法正常调试。那么,守护进程的进程要如何调试呢?一种通用的方法是使用 syslog 服务,将程序中的出错信息输入到系统日志文件中(如“/var/log/messages”),从而可以直观地看到程序的问题所在(“/var/log /message”系统日志文件只能由拥有root权限的超级用户查看。在不同的Linux发行版本中,系统日志文件路径全名可能有所不同,例如,我的Ubuntu中路径就是“/var/log/syslog”)。
syslog 是Linux中的系统日志管理服务,通过守护进程 syslogd 来维护。该守护进程在启动时会读一个配置文件“/etc/syslog.conf”,该文件决定了不同种类的消息会发送到何处。例如,紧急消息可被送到系 统管理员并在控制台上显示,而警告消息则可被记录到一个文件中。
该机制提供了3个syslog相关函数,分别为 openlog()、syslog()和closelog(),下面就分别介绍这3个函数。
函数说明
openlog()函数用于打开系统日志服务的一个链接;syslog()函数用于向日志文件中写入信息,在这里可以设定消息的优先级、消息输出格式等;closelog()函数用于关闭系统日志服务的链接。
函数格式
基础实验
咱们可以尝试用普通身份执行程序(RedHat中不要用root,ubuntu正常运行就可以)。由于这里的open()函数必须具有root权限,因此,syslog 会将错误信息写入到系统日志文件("如/var/log/syslog")中,结果如下图
本实验文件syslog_damen.c下载
免费下载地址在 http://linux.linuxidc.com/
用户名与密码都是www.linuxidc.com
具体下载目录在 /2013年资料/6月/12日/Linux多任务编程
Linux多任务编程之七:Linux守护进程及其基础实验(转)的更多相关文章
- Linux多任务编程之四:exit()函数及其基础实验(转)
来源:CSDN 作者:王文松 转自Linux公社 exit()和_exit()函数 函数说明 创建进程使用fork()函数,执行进程使用exec函数族,终止进程则使用exit()和_exit() ...
- Linux多任务编程之三:exec函数族及其基础实验(转)
来源:CSDN 作者:王文松 转自:Linux公社 exec函数族 函数族说明 fork() 函数用于创建一个新的子进程,该子进程几乎复制了父进程的全部内容,但是,这个新创建的子进程如何执行呢?e ...
- Linux网络编程学习(四) -----守护进程的建立(第三章)
本文介绍一个例程daemon_init() #include <sys/types.h> #include <signal.h> #include <unistd.h&g ...
- Linux多任务编程之六:编写多进程程序及其代码(转)
来源:CSDN 作者:王文松 转自Linux公社 ------------------------------------------------------------------------- ...
- Linux多任务编程之五:exit()和_exit()函数(转)
来源:CSDN 作者:王文松 转自:Linux公社 ----------------------------------------------------------------------- ...
- Linux中的两种守护进程stand alone和xinetd
Linux中的两种守护进程stand alone和xinetd --http://www.cnblogs.com/itech/archive/2010/12/27/1914846.html#top 一 ...
- Windows 和 Linux 上Redis的安装守护进程配置
# Windows 和 Linux 上Redis的安装守护进程配置 Redis 简介 Redis是目前最常用的非关系型数据库(NOSql)之一,常以Key-Value的形式存储.Redis读写速度 ...
- Linux多线程编程和Linux 2.6下的NPTL
Linux多线程编程和Linux 2.6下的NPTL 在Linux 上,从内核角度而言,基本没有什么线程和进程的区别--大家都是进程.一个进程的多个线程只是多个特殊的进程他们虽然有各自的进程描述结构, ...
- Python 3 并发编程多进程之守护进程
Python 3 并发编程多进程之守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemo ...
随机推荐
- 区分http请求状态码来理解缓存(协商缓存和强制缓存)
什么是http缓存呢,当我们使用chrome浏览器,按F12打开控制台,在网络请求中有时候看到状态码是200,有时候状态码是304,当我们去看这种请求的时候,我们会发现状态码为304的状态结果是:St ...
- 一次性搞懂 PHP 中面向对象的所有知识点。
OOP是什么? OOP是面向对象编程,面向对象编程是一种计算机编程架构. OOP的基本原则是计算机程序是由单个能起到子程序作用的单元或对象组合而成. 基本概念: 类:定义了事务的抽象特点.包含了数据的 ...
- render props的运用
2020-04-03 render props的运用 术语 “render prop” 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术 通常的 这个值为函数的prop ...
- 从零开始的Spring Boot(2、在Spring Boot中整合Servlet、Filter、Listener的方式)
在Spring Boot中整合Servlet.Filter.Listener的方式 写在前面 从零开始的Spring Boot(1.搭建一个Spring Boot项目Hello World):http ...
- APP自动化1——Appium+pycharm自动化环境搭建全流程
1. 安装python3,pycharm,可参考之前写的文档:https://www.cnblogs.com/chenweitoag/p/13154815.html 2. 准备以下必要工具: 基于wi ...
- 《Java并发编程的艺术》 第9章 Java中的线程池
第9章 Java中的线程池 在开发过程中,合理地使用线程池能带来3个好处: 降低资源消耗.通过重复利用已创建的线程 降低线程创建和销毁造成的消耗. 提高响应速度.当任务到达时,任务可以不需要等到线程创 ...
- CCNA-Part1:网络基础概念
由于身处一家网络公司,日常项目中设计到的网络概念较多,恰逢之后公司组织相关培训.借此机会,打算写下一系列文章用于之后梳理并回顾.文章主要涉及 NA,NP 中所覆盖的知识.由于网络分为较多方向,如路由交 ...
- android 中IntentService的使用场景
IntentService是继承并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统的Service一样,同时,当任务执行 ...
- LeetCode 80,不使用外部空间的情况下对有序数组去重
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题的第49篇文章,我们一起来看LeetCode的第80题,有序数组去重II(Remove Duplicates fr ...
- robot framework使用小结(三)
robot framework采用行为驱动 新建测试案例baidu04,添加Library:Selenium2Library 右键项目名robotProject-->New Resource-- ...