首页 > 代码库 > 守护进程
守护进程
通过一篇博客来记录守护进程的学习过程。
包括内容有下:
- 关于守护进程
- 守护进程的启动
- 如何创建守护进程
- 守护进程出错处理
关于守护进程
守护进程生长期比较长,通常系统自举的时候启动。是一种后台运行并且独立于所有终端控制之外的进程。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
守护进程
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。