zoukankan      html  css  js  c++  java
  • 在Linux下编写Daemon

    在Linux下编写Daemon

    转自:http://blog.163.com/prevBlogPerma.do?host=manyhappy163&srl=1644768312010718111142260&mode=prev

    在Linux(以Redhat Linux Enterprise Edition 5.3为例)下,有时需要编写Service。Service也是程序,一般随系统启动用户不干预就不退出的程序,可以称为Service。Linux下的Service一般称为Daemon。

    以上是广义的Service的定义。Linux下的Service一般放在/etc/init.d文件夹下。浏览一下这个文件夹下的文件,可以发现在Linux下编写Service一般遵循的原则。

    一 Linux下编写Service一般遵循的原则
    1)真正运行的Service一般放在某个bin目录下(/bin,/usr/bin,etc)。
    2)/etc/init.d文件夹下一般是shell脚本,用来控制bin目录下的Service。
    3)/etc/init.d文件夹下的shell脚本一般接受至少两个参数,start和stop。还有其他常用的可选参数如status,reload,restart,等。
    4)/etc/init.d文件夹下的shell脚本至少包括两行注释,一行告诉chkconfig此服务运行的runlevel,启动优先级,结束优先级。一行告诉chkconfig此服务的描述。
     

    二 Linux的启动过程和RunLevel
    要理解Linux的启动过程和RunLevel,可以先浏览一下/etc/inittab文件。在/etc/inittab中定义了下面7种RunLevel。每个Service可以设置自己在哪个RunLevel下运行。可以调用/sbin/init <runlevel>进入相应的RunLevel,比如运行/sbin/init 6就会导致系统重启。如果在某个RunLevel下某个服务不能启动,导致系统启动失败,可以进入没有配置此服务的RunLevel来禁用或修改此服务(有点类似Windows下的安全模式)。

    #   0 - halt (Do NOT set initdefault to this)
    #   1 - Single user mode
    #   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
    #   3 - Full multiuser mode
    #   4 - unused
    #   5 - X11
    #   6 - reboot (Do NOT set initdefault to this)


    /etc/inittab文件下还定义了缺省RunLevel。如下,代表缺省RunLevel是5。
    id:5:initdefault:
     

    在/etc文件夹下,执行ls -d rc*,会列出下面这些文件和目录:
    rc  rc0.d  rc1.d  rc2.d  rc3.d  rc4.d  rc5.d  rc6.d  rc.d  rc.local  rc.sysinit
    rc是一个脚本,在/etc/inittab中,会根据RunLevel执行rc <runlevel>。rc脚本会到相应的rcN.d中去执行下面的脚本。rc.local是最后调用的脚本,可以放一些用户自定义的任务在里面。

    进入rcN.d文件夹下,会发现以S和K开头的脚本的链接,S和K后面还带2位数字。其中S代表Start,K代表Kill。S开头的脚本,在rc中调用的时候会带start参数;K开头的脚本,在rc中调用的时候会带stop参数。S和K后面带的2位数字代表Service的优先级,数字越大,越后执行。这些脚本的链接的目的地多半都在/etc/init.d文件夹下。

    现在一切都清晰了。我们可以通过在相应的rcN.d文件夹下按既定的规范创建/etc/init.d下脚本的软链接的方式来控制系统启动和退出时服务的启动和结束。但是用手动的方式创建软链接来管理毕竟不方便,RedHatLinux提供了chkconfig来帮助创建这些软链接。只要放在/etc/init.d下的服务控制脚本符合前面提到的chkconfig的约定(注释chkconfig 和 description),就可以用chkconfig --add <service>  chkconfig --list <service> chkconfig --del <service>等命令来控制service的启动与否。
     

    三 一个例子
    1)下面是用c++语言写的一个Service,此Service在/tmp/random文件中,每隔5秒生成一个4位随机数字。通过g++ -o myrand myrand.cpp编译。然后把myrand放到/root/bin/文件夹下。

    /* myrand.cpp
     * this program read 4 chars from /dev/random in each iteration,
     * and then adjust it to 0-9. Finally the 4 chars are written
     * to /tmp/random. This is only for testing /dev/random, and
     * at the same time serve as a example service.
     
    */
    #include 
    <iostream>
    #include 
    <fstream>
    using namespace std;
    #include 
    <unistd.h> 

    int main()
    {
        
    while (true)
        {
                        ifstream ifile(
    "/dev/random");
                        
    char ch;
                        
    char str[5];
                        str[
    4]=0;
                        
    int i;
                        
    for(i=0;i<4;i++)
                        {
                                        ifile 
    >> ch;
                                        
    if(ch<0) ch=-ch;
                                        ch 
    = ch % 10;
                                        ch
    ='0' + ch;
                                        str[i]
    =ch;
                        }


                        ofstream ofile(
    "/tmp/random");
                        ofile 
    << str << endl;
                        sleep(
    5);
        }
    }

    2) 下面是一个脚本,名字是myrandservice,放在/etc/init.d文件夹下:

    #!/bin/sh
    #
    # chkconfig: 2345  80 50
    # description: myrandservice is for testing how to write service in Linux 
    #              
    # processname: myrandservice

    # Source function library.

    . /etc/rc.d/init.d/functions

    ret
    =0

    start() {
        
    # check fdb status
                    echo "start myrandservice"
                    daemon 
    /root/bin/myrand &
                    ret
    =$?


    stop() {
        echo 
    "stop myrandservice"
                    
    kill -9 $(ps -ef | grep myrand | grep -grep | awk '{print $2}')
                    ret
    =$?


    status() {
                    
    local result
                    echo 
    "check status of myrandservice..."
                    
    #lines=$( ps -ef | grep myrand | grep -v grep  |  )
                    #echo $lines

                    result=$( ps -ef | grep myrand | grep -v myrandservice | grep -grep | wc -l )
                    
    #echo $result
                    if [ $result -gt 0 ] ; then
                                    echo 
    "my randservice is up"
                                    ret
    =0
                    
    else
                                    echo 
    "my randservice is down"
                                    ret
    =1
                    fi
                    echo 
    "check status of myrandservice...done."


    # See how we were called.
    case "$1" in
      start)
            start
            ;;
      stop)
            stop
            ;;
      status)
            status 
            ;;
      
    *)
            echo $
    "Usage: $0 {start|stop|status}"
            
    exit 1
    esac

    exit $ret

    3)使用/sbin/chkconfig --add myrandservice 来将次daemon设置为自动启动。 同时可以在rc3.d,rc4.d,rc5.d下面看到相应的脚本链接被自动地创建了。

    4)例子的一些说明
    例子中脚本的下面两行既是给chkconfig用的。其中2345代表此服务在RunLevel 2, 3, 4, 5下开启;80代表启动优先级;50代表结束优先级。如果RunLevel处不添值,用“-”代替,则代表此服务在任何runlevel下都不会自动启动,需要手动启动。可以通过service <service-name> start/stop/status等来控制或查询Service。

    # chkconfig: 2345  80 50
    # description: myrandservice is for testing how to write service in Linux  

    脚本中的daemon函数存在于/etc/rc.d/init.d/functions中。daemon会重定向输出到/dev/null,也会设置是否生成coredump文件。通过daemon启动的程序,即使用户退出了命令行shell,也会保证Service会运行而不会退出。在/etc/rc.d/init.d/functions中还包括其他一些有用的函数,如killproc,status等,分别用来杀掉服务和查看服务状态。

    四 deamon的另一种实现

    不使用/etc/rc.d/init.d/functions中的daemon,则Daemon程序设计要遵从以下过程:

    (1)       程序运行后调用fork,并让父进程退出。子进程获得一个新的进程ID,但继承了父进程的进程组ID

    (2)       调用setsid创建一个新的session,使自己成为新session和新进程组的leader,并使进程没有控制终端(tty)

    (3)       设置文件创建mask0,避免创建文件时权限的影响。

    (4)       关闭不需要的打开文件描述符。因为Daemon程序在后台执行,不需要于终端交互,通常就关闭STDINSTDOUTSTDERR。其它根据实际情况处理。

    (5)       Daemon无法输出信息,可以使用SYSLOG或自己的日志系统进行日志处理。(可选)

    (6)       编写管理DaemonSHELL脚本,使用serviceDaemon进行管理和监控。(可选)

    参考:

    http://www.cnblogs.com/khler/archive/2011/01/30/1947971.html

    完!

  • 相关阅读:
    redis发布订阅
    redis学习笔记(面试题)
    redis安全 (error) NOAUTH Authentication required
    HDU3001 Travelling —— 状压DP(三进制)
    POJ3616 Milking Time —— DP
    POJ3186 Treats for the Cows —— DP
    HDU1074 Doing Homework —— 状压DP
    POJ1661 Help Jimmy —— DP
    HDU1260 Tickets —— DP
    HDU1176 免费馅饼 —— DP
  • 原文地址:https://www.cnblogs.com/itech/p/1937447.html
Copyright © 2011-2022 走看看