码迷,mamicode.com
首页 > 系统相关 > 详细

守护进程

时间:2014-12-31 18:12:24      阅读:256      评论:0      收藏:0      [点我收藏+]

标签:

通过一篇博客来记录守护进程的学习过程。

包括内容有下:

  1. 关于守护进程
  2. 守护进程的启动
  3. 如何创建守护进程
  4. 守护进程出错处理

关于守护进程

守护进程生长期比较长,通常系统自举的时候启动。是一种后台运行并且独立于所有终端控制之外的进程。Linux 系统通常有许多的守护进程,它们执行着各种系统服务和管理的任务。

守护进程的启动

要启动一个守护进程,可以采取以下的几种方式:
1.在系统期间通过系统的初始化脚本启动守护进程
2.很多网络服务程序是由inetd 守护程序启动的。在后面的章节中我们还会讲到它。它监听各种网络请求,如telnet、ftp 等,在请求到达时启动相应的服务器程序(telnet server、ftp server 等)。

技术分享
3.由cron 定时启动的处理程序。这些程序在运行时实际上也是一个守护进程。

技术分享
4.由at 启动的处理程序。
5.守护程序也可以从终端启动,通常这种方式只用于守护进程的测试,或者是重起因某种原因而停止的进程。(本文记录的是从终端启动)

守护进程刚开始学习阶段。没有试验过inetd,cron和at

如何创建守护进程

分为以下几个阶段:

1.调用umask将文件模式创建屏蔽字设置为0

2.调用fork,退出父进程,脱离终端

3.setsid()创建会话(session)

4.修改文件目录为根目录(/)

5.关闭所有文件描述符

/*************************************************************************
    > File Name: daemon.c
    > Author: ICKelin
    > Mail: 18277973721@sina.cn 
    > Created Time: 2014年12月18日 星期四 01时04分59秒
 ************************************************************************/

#include<stdio.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <syslog.h>
#include <signal.h>
#include <stdlib.h>

/*
 * 守护进程
 *  守护进程
 *  创建守护进程
 *        umask(0)
 *        fork()&exit(0)
 *        setsid()
 *        chdir()
 *        getrlimit&close(i)
 *
 * */
void daemonize(const char *cmd)
{
    int                    i,fd0, fd1, fd2;
    pid_t                pid;
    struct rlimit        rl;
    struct sigaction    sa;
    //清除
    umask(0);

    //获取最大文件描述符号
    if(getrlimit(RLIMIT_NOFILE, &rl) < 0)
        error("getrlimit");

    //会话组,进程组组长
    if( (pid = fork()) < 0)
        error("fork");
    else if(pid > 0)
        exit(0);        //停止父进程
    setsid();

    sa.sa_handler = SIG_IGN;        //忽略
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if(sigaction(SIGHUP, &sa, NULL) < 0)
        error("ignore SIGHUB");
    if((pid = fork()) < 0)
        error("fork");
    else if(pid != 0)
        exit(0);
    //修改当前工作路径
    if(chdir("/") < 0)
        error("chdir");
    //关闭文件描述符
    for(i = 0; i< rl.rlim_max; i++)
        close(i);
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);

    //初始化log
    openlog(cmd, LOG_CONS, LOG_DAEMON);
    if(fd0 !=0 || fd1 != 1 || fd2 != 2)
    {
        syslog(LOG_ERR,"unexpected file descriptors %d %d %d", fd0, fd1, fd2);
        exit(1);
    }
}

int main(int argc,char *argv[])
{
    daemonize("daemon");
}

服务器端守护进程

/*************************************************************************
    > File Name: demo04.c
    > Author: ICKelin
    > Mail: 18277973721@sina.cn 
    > Created Time: 2014年12月07日 星期日 15时17分48秒
 ************************************************************************/

#include"net.h"
#include <syslog.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/resource.h>

void daemonize(const char *cmd)
{
    int                    i,fd0, fd1, fd2;
    pid_t                pid;
    struct rlimit        rl;
    struct sigaction    sa;
    //清除
    umask(0);

    //获取最大文件描述符号
    if(getrlimit(RLIMIT_NOFILE, &rl) < 0)
        error("getrlimit");

    //会话组,进程组组长
    if( (pid = fork()) < 0)
        error("fork");
    else if(pid > 0)
        exit(0);        //停止父进程
    setsid();

    sa.sa_handler = SIG_IGN;        //忽略
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if(sigaction(SIGHUP, &sa, NULL) < 0)
        error("ignore SIGHUB");
    if((pid = fork()) < 0)
        error("fork");
    else if(pid != 0)
        exit(0);
    //修改当前工作路径
    if(chdir("/") < 0)
        error("chdir");
    //关闭文件描述符
    for(i = 0; i< rl.rlim_max; i++)
        close(i);
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);

    //初始化log
    openlog(cmd, LOG_CONS, LOG_DAEMON);
    if(fd0 !=0 || fd1 != 1 || fd2 != 2)
    {
        syslog(LOG_ERR,"unexpected file descriptors %d %d %d", fd0, fd1, fd2);
        exit(1);
    }
}

int main(int argc,char *argv[])
{
    if(argc != 2)
        error("arguemtne");
    daemonize("server");
    unsigned int port = atoi( argv[1]);
    
    int server = setup(port);
    if(server ==-1)
        error("setup");

    fprintf(stdout,"server start\nlistenning port %d\n",port);
    struct sockaddr_storage client_addr;
    unsigned int address_size = sizeof(client_addr);
    
    while(1)
    {
        int client = accept(server,(struct sockaddr*)&client_addr,&address_size);
        do_connect(client,client_thread,(void *)client);
    }
    close(server);
    return 0;
}

net.h头文件

/*************************************************************************
    > File Name: demo03.c
    > Author: ICKelin
    > Mail: 18277973721@sina.cn 
    > Created Time: 2014年12月07日 星期日 11时53分24秒
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<errno.h>
#include<pthread.h>
#include<unistd.h>

static int count = 0;

/* 致命错误处理包裹函数 */
void error(char *msg)
{
    fprintf(stderr,"%s error with:%s\n",msg, strerror(errno));
    exit(1);
}

/* 服务器启动函数 
 * 接收端口号
 * 绑定,监听
 * 返回服务器端套接字描述符
 *
 * */
int setup(unsigned int port)
{
    struct sockaddr_in server_sock;
    int fd = -1;
    fd = socket(PF_INET, SOCK_STREAM, 0);

    int reuse = 1;
    if(setsockopt(fd,SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(int)) == -1)
        error("set reuse");
    if(fd == -1)
        error("socket");
    server_sock.sin_family = PF_INET;
    server_sock.sin_port = (in_port_t)htons(port);
    server_sock.sin_addr.s_addr = htonl(INADDR_ANY);

    int c = bind(fd, (struct sockaddr *)&server_sock, sizeof(server_sock));
    if(c == -1)
        error("bind");
    if(listen(fd,10) == -1)
        error("listen");
    return fd;
}

/* 连接处理线程
 *
 * 接收连接套接子描述符
 * 处理请求
 * 返回空
 * */

void client_thread(int connect_d)
{
    char *msg = "welcome to my server --ICKelin\n";
    
    fprintf(stdout,"new connect, current connect count %d\n",++count);
    sleep(5);
    if(send(connect_d, msg, strlen(msg),0) <0)
    {
        error("send");
    }

    close(connect_d);
    count--;
}

/*
 * 处理连接
 * 接收客户端连接,和处理线程
 * 返回空
 * */

void do_connect(int connect_d,void *func,void *args)
{
    pthread_t newthread;
    if ( pthread_create(&newthread,NULL,func,args) == -1)
        error("pthread_create");
}

/*
 * 关闭连接
 * */
void close_connect(int fd)
{
    close(fd);
}

由于前后编写时间间隔比较长,代码前后搭配不当,正确的做法是,将net.h里面输出到标准输出,标准错误相关代码利用syslog输出到日志。

编译执行

hadoop@ICKelin:~/Network/2014_12_07$ gcc demo04.c -lpthread -o myserver1111111
hadoop@ICKelin:~/Network/2014_12_07$ ./myserver1111111 5002
hadoop@ICKelin:~/Network/2014_12_07$ ps -axj|grep myserver1111111 
Warning: bad ps syntax, perhaps a bogus -? See http://procps.sf.net/faq.html
    1  8313  8312  8312 ?           -1 S     1000   0:00 ./myserver1111111 5002
 8035  8319  8318  8035 pts/0     8318 S+    1000   0:00 grep --color=auto myserver1111111
hadoop@ICKelin:~/Network/2014_12_07$ 

用kill杀死。kill 8313

守护进程

标签:

原文地址:http://www.cnblogs.com/ickelin/p/4181148.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!