加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Ubuntu 创建守护进程实例

(2009-09-28 16:47:48)
标签:

linux

守护进程

实例

分类: *C/CPlusPlus
// MyDameon.cpp
#include "stdio.h>
// 双引号变尖括号
#include "stdlib.h>
#include "string.h>
#include "fcntl.h>
#include "sys/types.h>
#include "unistd.h>
#include "sys/wait.h>
#include "syslog.h>
#define MAXFILE 65535

int main()
{
    pid_t pid;

    // 第一步 - 子进程创建成功,父进程退出
    pid = fork(); 

    if ( pid < 0 )
    {
         printf( "error fork\n" );
         exit( -1 );
    }
    else if ( pid > 0 )
    {
         exit( 0 );
    }

    // 打开系统日志服务
    openlog( "MyDaemon",       // 应用程序名
                   LOG_PID,    // 在每条消息中包含进程的PID
                   LOG_USER ); // 一般使用者等级信息

    // 第二步 - 为子进程创建新会话期,即摆脱原会话期、原进程组、原控制终端的控制
    if ( 0 > setsid() )
    {
         // syslog 就会将错误信息写入到“/var/log/messages”中
           syslogLOG_INFO,            // 信息消息
                     "%s\n",            // 信息格式
                     "setsid failed!"); // 要输出的信息
         exit( -2 );
    }

    // 第三步 - 将当前工作目录改为根目录
    if ( 0 > chdir( "/" ) )
    {
         // syslog 就会将错误信息写入到“/var/log/messages”中
         syslogLOG_INFO            // 信息消息
                     "%s\n",           // 信息格式
                     "chdir failed!"); // 要输出的信息
         exit( -3 );
    }

    // 第四步 - 文件权限全无
    umask( 0 );

    // 第五步 - 关闭所有打开的文件,包括标准输入/出,错误输出
    int i = 0;
    for ( i = 0;
          i < MAXFILE;
          i++)
    {
            close( i );
    }

    // 到此处已经创建完守护进程,以下开始编写守护进程工作代码
    // 这里只是举个例子, syslog 将信息写入到“/var/log/messages”中
    // 以下只需替换成根据实际情况而编写的代码即可!
    syslogLOG_INFO                // 信息消息
                "%s\n",               // 信息格式
                "this a test info!"); // 要输出的信息
    // 休息五秒
    sleep(5);

    // 最后,别忘了关闭系统日志服务
    closelog();

    exit( 1 );
}

在 [终端] 上输入以下命令,可以实时看到最新日志记录,ctrl + c退出!
tail -f /var/log/messages
如下就是上面输出的记录:
Sep 29 11:07:17 wzhnsc-desktop MyDaemon[13590]: this a test info!

方括号前的是openlog函数的第一个参数,即应程序名。方括号里的是openlog函数的第二个参数,LOG_PID,即在每条消息中包含进程的PID。冒号后面的是syslog函数输出的记录文本。
INIT 进程的一个重要作用就是启动 Linux 系统服务(也就是运行在后台的守护进程) 。
Linux 的系统服务包括两种:
第一种是独立运行的系统服务,它们常驻内存中,自开机后一直启动着(如 httpd),具有很快的响应速度;
第二种是由 xinet 设定的服务。
xinet 能够同时监听多个指定的端口,在接受用户请求时,它能够根据用户请求的端口不同,
启动不同的网络服务进程来处理这些用户请求。
因此,可以把 xinetd 看作一个启动服务的管理服务器,它决定把一个客户请求交给那个程序处理,然后启动相应的守护进程。


以下来分别介绍这两种系统服务。

独立运行的系统服务的启动脚本都放在目录“/etc/init.d/”中(Ubuntu 9.04)。
ls /etc/init.d

为了指定特定运行级别服务的开启或关闭,系统的各个不同运行级别都有不同的脚本
文件,其目录为“/etc/rc.d/rcN.d”,其中的 N 分别对应不用的运行级别的数字。
ls /etc/rc3.d

可以看到,每个对应的服务都以“K”或“S”开头,
其中的 K 代表关闭(kill),其中的 S 代表启动(start),
用户可以使用命令“+start|stop|status|restart”来对相应的服务进行操作。

INIT在执行完相应的 rcN.d 目录下的脚本文件后,INIT 最后会执行 rc.local 来启动本地服务,因此,用户若想把某些非系统服务设置为自启动,可以编辑 rc.local 脚本文件,加上相应的执行语句即可。

另外,读者还可以使用命令“service+系统服务+操作”来方便地实现相应服务的操作,如下所示:
service xinetd restart
xinetd 设定的服务xinetd 管理系统中不经常使用的服务,这些服务程序只有在有请求时才由 xinetd 服务负责启动,一旦运行完毕服务自动结束。
xinetd 的配置文件为“/etc/xinetd.conf”,它对 xinet 的默认参数进行了配置:

#
# Simple configuration file for xinetd
#
# Some defaults, and include /etc/xinetd.d/
defaults
{
   instances = 60
   log_type = SYSLOG authpriv
   log_on_success = HOST PID
   log_on_failure = HOST
   cps = 25 30
}
includedir /etc/xinetd.d

从该配置文件的最后一行可以看出,xinetd 启动“/etc/xinetd.d”为其配置文件目录。
再在对应的配置文件目录中可以看到每一个服务的基本配置,如 tftp 服务的配置脚本文件为:
service tftp
{
   socket_type = dgram // 数据包格式
   protocol = udp // 使用 UDP 传输
    wait = yes
    user = root
    server = /usr/sbin/in.tftpd
    server_args = -s /tftpboot
    disable = yes // 不启动
    per_source = 11
    cps = 1002
    flags = IPv4
}

设定系统服务除了上面提到的使用 service 之外,chkconfig 也是一个很好的工具,它能够为不同的系统级别设置不同的服务。

1)chkconfig --list(注意在 list 前有两个小连线) :查看系统服务设定。

示例: chkconfig --list2)chkconfig --level N [服务名称] 指定状态:对指定级别指定系统服务。
示例: chkconfig --level 3 ntpd on

#include "unistd.h" // 双引号变尖括号
#include "signal.h"
#include "sys/param.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "stdio.h"
#include "time.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;
}

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

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有