`
jiangshuiy
  • 浏览: 339314 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

守护进程与setsid

阅读更多
守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进 程。 Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任务。 比如,作业规划进程crond,打印进程lpd等。

守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同 Unix环境下守护进程的编程规则并不一致。需要注意,照搬某些书上的规则(特别是BSD4.3和低版本的System V)到Linux会出现错误的。下面将给出Linux下守护进程的编程要点和详细实例。

一. 守护进程及其特性

守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。其次,守护进程必须与其运行前的环境隔离开来。这些环 境包括未关闭的文件描述符,控制终端,会话和进程组,工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下 来的。最后,守护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc*.d中启动,可以由作业规划进程crond启动,还 可以由用户终端(通常是 shell)执行。

总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。如果对进程有比较深入的认识就更容易理解和编程了。

二. 守护进程的编程要点

前面讲过,不同Unix环境下守护进程的编程规则并不一致。所幸的是守护进程的编程原则其实都一样,区别在于具体的实现细节不同。这个原则 就是要满足守护进程的特性。同时,Linux是基于Syetem V的SVR4并遵循Posix标准,实现起来与BSD4相比更方便。编程要点如下;

1. 在后台运行。

为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。

if(pid=fork())exit(0); //是父进程,结束父进程,子进程继续
2. 脱离控制终端,登录会话和进程组

有必要先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。 控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第1点的基础上,调用setsid()使进程成为会话组长:

setsid();

说明:当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。

3. 禁止进程重新打开控制终端

现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:

if(pid=fork()) exit(0); //结束第一子进程,第二子进程继续(第二子进程不再是会话组长)

4. 关闭打开的文件描述符

进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关闭它们:

for(i=0;i<;++1) //关闭打开的文件描述符
close(i);

5. 改变当前工作目录

进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心,写运行日志的进程将工作目录改变到特定目录如 /tmpchdir("/")

6. 重设文件创建掩模

进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0);

7. 处理SIGCHLD信号

处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结 束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下 可以简单地将 SIGCHLD信号的操作设为SIG_IGN。

signal(SIGCHLD,SIG_IGN);

这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程。

三. 守护进程实例

守护进程实例包括两部分:主程序test.c和初始化程序init.c。主程序每隔一分钟向/tmp目录中的日志test.log报告运行状态。初始化程序中的init_daemon函数负责生成守护进程。读者可以利用init_daemon函数生成自己的守护进程。

1. init.c清单

#include < unistd.h >
#include < signal.h >
#include < sys/param.h >
#include < sys/types.h >
#include < sys/stat.h >

void init_daemon(void){
    int pid;
    int i;
    if(pid=fork())exit(0);//是父进程,结束父进程
     else if(pid< 0)exit(1);//fork失败,退出

    //是第一子进程,后台继续执行
    setsid();//第一子进程成为新的会话组长和进程组长
               //并与控制终端分离
    if(pid=fork())exit(0);//是第一子进程,结束第一子进程
    else if(pid< 0)exit(1);//fork失败,退出

    //是第二子进程,继续
    //第二子进程不再是会话组长

     for(i=0;i< NOFILE;++i)//关闭打开的文件描述符
     close(i);
    chdir("/tmp");//改变工作目录到/tmp
    umask(0);//重设文件创建掩模
     return:
}

2. test.c清单

#include < stdio.h >
#include < time.h >
#include < stdio.h >

void init_daemon(void);//守护进程初始化函数
main(){
    FILE *fp;
    time_t t;
    init_daemon();//初始化为Daemon
    while(1)//每隔一分钟向test.log报告运行状态
    {
        sleep(60);//睡眠一分钟
         if((fp=fopen("test.log","a")) >=0){
        t=time(0);
        fprintf(fp,"Im here at %sn",asctime(localtime(&t)) );
        fclose(fp);
        }
    }
}


以上程序在Ubuntu Linux8.04下编译通过。步骤如下:

编译:gcc -g -o test init.c test.c

执行:./test

查看进程:ps -ef

从输出可以发现test守护进程的各种特性满足上面的要求。 


分享到:
评论

相关推荐

    编写Linux守护进程.pdf

    2. **环境隔离**:守护进程需与启动它的环境隔离,包括关闭所有继承自父进程(如shell)的文件描述符,如标准输入、输出和错误流,以及释放与终端相关的资源。 3. **启动方式多样**:守护进程可以手工启动,也可以...

    Linux系统中守护进程的创建方法.pdf

    守护进程与 Windows 中的后台服务程序比较类似,如 Windows 中有一种 time 系统服务,用来从远程主机获得日期和时间,Linux 中也有类似 的两个守护进程 time 和 time-udp,分别采用 TCP 和 UDP 协议从远程主机获得...

    Linux系统下守护进程编程方法

    #### 二、守护进程与一般进程的区别 在Linux系统中,每个进程都有其独特的进程标识号(PID),初始进程为1号进程Init,由其派生出其他所有进程。进程之间通过父子关系关联,每个进程属于一个进程组,拥有相同的进程...

    C语言编写linux下的守护进程

    Linux下的守护进程编写指南 在 Linux 操作系统中,守护进程(Daemon)是一种特殊类型的进程,它在后台...通过使用 fork 函数、setsid 函数、close 函数、chdir 函数和 umask 函数,我们可以编写一个简单的守护进程。

    基于Linux守护进程的分析与实现.pdf

    【守护进程的概念与作用】 守护进程(Daemon)是Linux操作系统中的一个重要组成部分,它们在后台运行,不与用户交互,主要用于提供系统服务。例如,网络服务、时间同步、打印服务等都由守护进程来执行。守护进程...

    python编写守护进程实现当python进程被杀后重启进程的源代码

    在Python编程中,守护进程(Daemon)是一种特殊类型的后台进程,它不依附于终端,且能在系统启动时启动,并在系统关闭时终止。守护进程常用于提供持续的服务,例如Web服务器、数据库服务等。本篇文章将深入探讨如何...

    daemon守护进程经典

    守护进程(daemon)是Linux和Unix-like操作系统中的一个重要概念,它们是后台运行的程序,不与任何终端直接关联,主要用于提供系统服务,如网络服务、日志记录、打印队列等。守护进程在系统启动时启动,持续运行直到...

    如何调试守护进程

    在IT领域,守护进程(Daemon)是运行在后台的特殊类型进程,它们通常不与终端交互,而是持续地执行特定任务,例如网络服务、日志记录等。调试守护进程是一项技术性较强的工作,因为它们的运行环境和普通进程有所不同...

    Linux守护进程的编程方法.pdf

    2. **与环境隔离**:守护进程需要与创建它的环境进行隔离,包括关闭未使用的文件描述符、脱离控制终端、会话和进程组、改变工作目录以及清除文件创建掩模等。 3. **启动方式**:守护进程可以通过多种方式启动,比如...

    如何写守护进程

    ### 如何编写守护进程 守护进程(Daemon Process)是一种在后台持续运行的进程,它不依附于任何用户终端并且独立于控制台之外。守护进程主要用于执行特定的任务或提供服务,例如日志管理、定时任务处理等。本文将...

    守护进程源码

    1. **无控制终端**:守护进程不与任何终端关联,不受用户的交互操作影响。 2. **后台运行**:守护进程在后台执行,不会占用用户界面。 3. **持久性**:守护进程常驻内存,直到系统关闭或者被显式停止。 4. **资源...

    编写Linux守护进程

    Linux/Unix 守护进程是指在后台运行的进程,不与控制终端交互,独立于控制终端的输入/输出操作。编写 Linux 守护进程需要了解多个概念,如子进程、进程组、会晤期、信号机制、文件、目录和控制终端等。 要编写一个 ...

    守护进程介绍

    【守护进程介绍】 守护进程(Daemon)是Linux和Unix操作系统中的关键组成部分,它们在系统启动时启动,并在后台持续运行,提供各种服务。守护进程的主要特点是脱离终端,不会受到终端活动的影响,允许它们独立地...

    linux守护进程

    在Linux系统中,守护进程是一种后台服务程序,它们在启动后与控制终端脱离,并在后台持续运行,为用户提供服务或者执行特定的任务。守护进程是操作系统中最常见的进程类型之一,如网络服务(HTTP服务器如Apache)、...

    守护进程(C语言写的360绝对杀不死)

    守护进程(Daemon)在计算机系统中扮演着至关重要的角色,它是后台运行的程序,通常不与用户交互,而是为其他服务或系统提供支持。在Linux和Unix-like操作系统中,守护进程广泛用于网络服务、系统管理任务以及持续...

    守护进程实例(很实用的编程技巧)

    1. **脱离控制终端**:守护进程不应与任何终端相关联,所以首先要断开与父进程的关联并关闭所有标准输入、输出和错误流。 2. **改变工作目录**:守护进程应将当前工作目录更改为根目录(/),以避免占用用户目录资源...

    守护进程范例

    1. **脱离控制终端**:守护进程首先需要断开与当前终端的连接,这可以通过设置`setsid()`函数实现,它会创建一个新的会话并使进程成为该会话的会话组长,从而脱离父终端。 2. **改变工作目录**:为了避免守护进程...

    Linux以守护进程方式运行的信息服务器

    【守护进程】在Linux系统中,守护进程(Daemon)是一种在后台运行且不与终端关联的进程,通常用于提供持续性的服务。守护进程在启动时会脱离控制终端,避免受到用户登录登出的影响,以便长期稳定地运行。守护进程常...

    PHP 守护进程 源码

    在IT领域,尤其是在服务器端开发中,守护进程(Daemon)是一种长期运行的后台程序,它不与任何终端关联,常驻内存,以便随时响应服务请求。PHP作为一种流行的服务器端脚本语言,虽然最初设计用于处理HTTP请求,但...

Global site tag (gtag.js) - Google Analytics