linux守护进程 编写要点

来源:互联网 发布:中国建筑业知乎 编辑:程序博客网 时间:2024/06/06 07:36
   守护进程(Daemon)是运行在后台的一种特殊进程,脱离于终端。它在执行过程中产生的信息也不会在终端上显示。守护进程周期性地执行某种任务或等待处理某些事件的发生。Linux的大多数服务器就是用守护进程实现的。
编写要点:(最后有完整示例)
1.屏蔽一些有关终端操作的信号。这是为了防止在守护进程还没有正常运行起来前,受到终端干扰退出或者挂起。代码:
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGHUP, SIG_IGN);
2.在后台运行。为避免挂起控制终端将其放入后台执行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。代码:
if( (pid = fork()) > 0)    exit(0);    //父进程,结束父进程,子进程继续
3.脱离控制终端和进程组。代码:
setsid();  //刚才fork的子进程调用
调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。
4.禁止进程重新打开控制终端。现在,进程已经成为无终端的会话组长,并且该会话没有控制终端,但会话组长可以重新申请打开一个控制终端。所以要让进程不是会话组长,来禁止进程重新打开控制终端。代码:
if( (pid = fork()) > 0)
   exit(0);  //之前的子进程结束,子子进程继续运行
此时的进程组id、会话id是之前子进程的pid,现在程序运行的是子子进程。虽然刚才的会话组长结束了,但是它pid还在,因为进程组、会话的生命期结束消失是在这个组、会话中所有进程都结束时才发生的。
5.关闭打开的文件描述符。进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。代码:
#define MAX_FILENO 1024
for(i = 0; i < MAX_FILENO; ++i)
  close(i);
程序能打开的文件最大个数,在头文件<linux/limits.h>中 NR_OPEN 指定,查看并使用此值。
6.改变当前工作目录。进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。写运行日志的进程将工作目录改变到特定目录如/tmp。代码:
chdir("/");
7.重设文件创建掩码。进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除。代码:
umask(0);
8.处理SIGCHLD信号。对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将 SIGCHLD信号的操作设为SIG_IGN来解决问题。代码:
signal(SIGCHLD, SIG_IGN);
上面说了这么多都是守护进程的编写要点,值得一提的是系统已经给我们提供了API让进程直接成为守护进程:

#include <unistd.h>

int daemon(int nochdir, int noclose);  //使进程成为守护进程

//0,则改变工作目录到“/”; 0,则重定向stdin、stdout、stderr到“/dev/null”

此外,守护进程可以与日志守护进程建立联系,将日志信息写入日志文件。用到的函数:
#include <syslog.h>
void openlog(const char *ident, int option, int facility);
//打开当前程序与日志守护进程之间的联系。
ident,是一个标记,ident所表示的字符串将固定地加在每行日志的前面以标识这个日志,通常就写成当前程序的名称以作标记。
option,一般是下列选项值取“与”运算(使用“|”表示,如“LOG_CONS | LOG_PID”)的结果:
  LOG_CONS:如果送到system logger时发生问题,直接写入系统终端;  LOG_NDELAY:立即开启连接,通常连接是在第一次写入消息时才打开的;
    LOG_NOWAIT: Don't wait for child processes that may have  been  created while logging the message.  
               (The GNU C library does not create a child process, so this option has no effect on Linux.)
    LOG_ODELAY:The converse of LOG_NDELAY; opening of the connection is delayed until syslog() is called.
               (This is the default,and need not be specified.)  LOG_PERROR:将消息也同时送到stderr设备;  LOG_PID:将进程PID含入所有消息中。
facility,指明记录日志的程序的类型,它主要具有如下几类日志类型:  LOG_AUTH :安全/授权消息  LOG_AUTHPRIV:安全/授权消息(私有)  LOG_CRON:时间守护进程(cron和at)专用  LOG_DAEMON:其它系统守护进程  LOG_KERN:核心消息  LOG_LOCAL0到LOG_LOCAL7:系统保留  LOG_LPR:printer子系统  LOG_MAIL:mail子系统  LOG_NEWS:USENET新闻子系统  LOG_SYSLOG:syslogd进程内部所产生的消息  LOG_USER(缺省):一般使用者缺省使用消息  LOG_UUCP:UUCP子系统  LOG_FTP:FTP子系统使用
void syslog(int priority, const char *format, ...);
//产生一条日志信息,然后由日志守护程序将其发送到各日志文件。
level priority,紧急级别:
    LOG_EMERG:紧急状况
  LOG_ALERT:高优先级问题,比如说数据库崩溃等,必须要立即采取反应行动  LOG_CRIT:重要状况发生,比如硬件故障  LOG_ERR:错误发生  LOG_WARNING:警告发生  LOG_NOTICE:一般状况,需要引起注意  LOG_INFO:信息状况  LOG_DEBUG:调试消息
第二个参数是消息及其格式,之后是格式对应的参数,如同C语言里面printf输出函数一样使用。
  在实际使用中,如果我们的程序要使用系统日志功能,只需要在程序启动时使用openlog函数来连接syslogd程序,后面随时用syslog函数写日志就行了。
void closelog(void);
//关闭日志。虽然这个函数简单,但必不可少,因为日志也是资源,只打开不管可能会造成内存不足。
守护程序完整示例:
#include <unistd.h>#include <signal.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/syslog.h>#include <sys/param.h>#include <stdio.h>#include <stdlib.h>#include <time.h>#define MAX_FILENO 1024int init_daemon(){int pid;int i;signal(SIGTTOU,SIG_IGN);signal(SIGTTIN,SIG_IGN);signal(SIGTSTP,SIG_IGN);signal(SIGHUP ,SIG_IGN);if( (pid = fork()) > 0){exit(EXIT_SUCCESS);}else if(pid< 0){perror("fork");exit(EXIT_FAILURE);}setsid();if( (pid = fork()) > 0){exit(EXIT_SUCCESS);}else if(pid< 0){perror("fork");exit(EXIT_FAILURE);}for(i = 0; i < MAX_FILENO; ++i){close(i);}open("/dev/null", O_RDONLY);open("/dev/null", O_RDWR);open("/dev/null", O_RDWR);chdir("/tmp");umask(0);signal(SIGCHLD,SIG_IGN);return 0;}int main(int argc,char *argv[]){init_daemon();openlog("MyLog", LOG_PID, LOG_KERN);while(1){sleep(1);syslog(LOG_INFO,"This is my log : %s\n",argv[0]);}}
此时,ps -axj,显示:          
PPID   PID  PGID   SID  TTY   TPGID STAT   UID   TIME  COMMAND
 1    4613  4612   4612  ?     -1    S     1000   0:00  ./main
打开/var/log/messages 文件:
MyLog[4613]: This is my log : ./main
	
				
		
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 韵达快递不派件怎么办 中通快递不派件怎么办 理财回执单丢失怎么办 理财回单丢了怎么办 杭州市老年优待卡怎么办 网络连接不到服务器怎么办 即时库存有负数怎么办 电脑软件被拦截怎么办 超市无条码商品怎么办 场外期权有诈骗怎么办 ip地址访问受限怎么办 电脑ip地址受限怎么办 百度云资源打不开怎么办 百度网盘看文件字太小怎么办 密码输入三次错误怎么办 notes邮箱满了怎么办 小米8买不到怎么办 小米付款不发货怎么办 小米金融还款中怎么办 股票遇到闪崩怎么办 微信插件没有怎么办 excel打印太小怎么办 工地临时人员死亡怎么办 哺乳期乳腺增生疼怎么办 哺乳期有乳腺增生怎么办 哺乳期得了乳腺增生怎么办 中等教育认证花名册丢失怎么办 哺乳期囊性结节怎么办 乳腺增生堵奶怎么办 月子期乳房增生怎么办 母乳期乳腺增生怎么办 上市公司破产了股票怎么办 iptv错误码30022怎么办 电信iptv不清晰怎么办 电信iptv卡顿怎么办 pr滚动字幕闪烁怎么办 电视车表盘看不清怎么办 图片字看不清楚怎么办 字太潦草看不清怎么办 微信图片看不清怎么办 小车上坡没动力怎么办