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 ...
随机推荐
- 移动UI系列 - 简单地使用半衰期算法来预测手势的滑动方向与速度
前言 有一个问题, 给定一个物体的运动轨迹, 包含时间和坐标的数组, 如何使用这个数据来预测物体未来的运动走势?? 本文提供了一个很简单的方式去实现这个算法. 效果够用, 又简单, 有一定的准确程度. ...
- Windows10 搭建 ElasticSearch 集群服务
一.前言 集群的搭建需要多台机器,之前我使用 ubuntu 16.04 搭建过 hadoop 的单机模式和分布式模式,这个今后会写,今天先写一篇使用 < Windows10 搭建 Elastic ...
- 拉勾网 + selenium
目录 方式一 selenium 方式二普通方法 方式一 selenium from selenium import webdriver import time from selenium.webdri ...
- 启动centos 不带桌面
方法一:非systemd系统 #runlevel N 5 //表示运行级别为5 #init 3 //将运行级别设为3,此时桌面服务关闭 运行级别说明: 3 多用户模式.允许多用户登录系统,是系统默认的 ...
- UIPopoverPresentationController的使用
前言 最近项目中很多地方有一个相同的需求,那就是点击一个按钮的时候在按钮的某一个方向弹出一个视图,这个视图需要带有一个箭头指向,就像下图一样.要实现这个功能,就要用到UIPopoverPresenta ...
- java中Proxy类初探
在java中提供了一个动态代理类,这个类位于java.lang.reflect包中的Proxy类中.什么是动态代理类呢?就是可以在运行时创建一个实现了一组给定接口的新类.听上去有点高深的样子,其实是提 ...
- python的坑--你知道吗?
python的坑--你知道吗? 1.列表的坑 坑的地方是:因为列表用pop之后,后面的索引都会自动减一 # 列表的坑之一 list1 = ['python','java','php','c','c++ ...
- async/await剖析
async/await剖析 JavaScript是单线程的,为了避免同步阻塞可能会带来的一些负面影响,引入了异步非阻塞机制,而对于异步执行的解决方案从最早的回调函数,到ES6的Promise对象以及G ...
- 33_栈程序演示.swf
pBottom执行栈底有效元素的前一个节点,该节点没有存储有效数据,这样设计是便于栈的管理,向链表一样pHead指向链表的第一个节点,该节点是不存储有效数据的 pTop执行栈顶最新的节点 如果pTop ...
- android屏幕适配的全攻略--支持不同的屏幕尺寸适配平板和手机
一. 核心概念与单位详解 1. 什么是屏幕尺寸.屏幕分辨率.屏幕像素密度? 屏幕分辨率越大,手机越清晰 dpi就是dot per inch dot意思是点,就是每英寸上面的像素点数 android原始 ...