首页 > 代码库 > 守护进程

守护进程

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

包括内容有下:

  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 myserver1111111hadoop@ICKelin:~/Network/2014_12_07$ ./myserver1111111 5002hadoop@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 myserver1111111hadoop@ICKelin:~/Network/2014_12_07$ 

用kill杀死。kill 8313

守护进程