- UID
- 1
- 精华
- 积分
- 76361
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
写“呆萌”,也就是后台守护进程(“Daemon”的谐音是“呆萌”),需要注意以下几点:
1、用户如果用ssh控制他的服务器,然后服务器跑了你的呆萌,当用户断开ssh连接的时候,你的呆萌也能继续运行。
2、你的呆萌应该把运行的过程写入到日志里,而不是输出到屏幕上。
3、保证稳定性,别因为无视了一个signal而挂掉。
4、为了便于管理,你应该在临时文件夹写一个lock文件,里面用文本记录你的PID号,以便于用户用脚本控制你的呆萌进程(典型的,使其能兼容chkconfig的配置方式)
一般来说你的守护进程被直接运行的时候,它的父进程应该是bash,然后bash会一直等待你的进程结束,才会继续执行后面的脚本。
为了能让你的程序不堵住bash的脚本执行过程,一般的做法是启动一个新的进程,然后旧进程退出,让bash继续执行,而新进程则作为呆萌保持执行过程。
这里最常用的函数就是fork()了,它在unistd.h里面有定义,这个函数的作用是:- 复制自身进程,新的进程拥有完全一样的内存空间(但它一般并不需要完全复制自身的内存数据,虽然此时新的进程的内存数据和旧进程完全相同)。
- 如果自己是父进程,返回子进程的PID;如果自己是子进程,返回0;如果分身失败,则返回-1.
调用fork()后,旧进程就可以退出了,然后bash继续运行,与此同时你的新进程也在后台运行。但这还不够,因为此时你的旧进程和新进程都不是一个进程组的组长,因此当你的旧进程被杀的时候,新进程也会死。此时你需要调用setsid()来设置新的进程会话ID,也就是让你的新进程成为一个进程组的组长,这样的话它就真正从父进程独立出来了。
此时新进程需要做的事情有以下几个:- 把PID写到lock文件里,便于让用户找到你。
- 关闭没用的文件描述符,比如stdin,stdout和stderr,或者你把stdout和stderr重定向到你的log,但其实自己fopen一个新的fd比做一次重定向方便得多。
- 设置信号(signal)处理,将无关信号屏蔽,然后对SIGPIPE、SIGHUP、SIGTERM做出响应。
这里给一份例子,展示一个程序如何进入呆萌模式。- // 需要的头文件
- #include<stdio.h>
- #include<signal.h>
- #include<stdarg.h>
- #include<unistd.h>
- // 程序信息
- #define EXEC_NAME foo
- #define LOCK_FILE "/var/tmp/"EXEC_NAME".lock"
- #define LOG_FILE EXEC_NAME".log"
- static volatile int g_Quit = 0; // 是否退出
- static void _signal_handler(int sig);
- void Inst_Log(char *format, ...); // 记录log
- //==============================================================================
- //Func: _Inst_Daemonize
- //Desc: Make program run as a daemon
- //------------------------------------------------------------------------------
- static int _Inst_Daemonize()
- {
- int i,lfp;
- char str[10];
-
- if(getppid() == 1)
- {
- fprintf(stderr, EXEC_NAME" was still running.\n");
- return 0;
- }
-
- i = fork();
- if(i < 0)
- {
- // fork error
- return 0;
- }
- if(i > 0)
- {
- // Parent exits, child (daemon) continues
- return 0;
- }
-
- setsid(); // obtain a new process group
-
- fclose(stdin);
- fclose(stdout);
- fclose(stderr);
-
- lfp=open(LOCK_FILE,O_RDWR|O_CREAT,0644);
- if(lfp<0)
- {
- // Could not open lock file.
- Inst_Log("Open lock file failed.\n");
- return 0;
- }
-
- if(lockf(lfp, F_TLOCK, 0) < 0)
- {
- // can not lock
- Inst_Log("Lock lock file failed.\n");
- return 0;
- }
-
- // first instance continues
- sprintf(str,"%d\n",getpid());
- write(lfp,str,strlen(str)); // record pid to lockfile
-
- signal(SIGCHLD,SIG_IGN); // ignore child
- signal(SIGTSTP,SIG_IGN); // ignore tty signals
- signal(SIGTTOU,SIG_IGN);
- signal(SIGTTIN,SIG_IGN);
- signal(SIGPIPE,SIG_IGN);
- signal(SIGHUP,_signal_handler); // catch hangup signal
- signal(SIGTERM,_signal_handler); // catch kill signal
-
- return 1;
- }
- //==============================================================================
- //Func: Inst_Log
- //Desc: Print log to a specified file.
- //------------------------------------------------------------------------------
- void Inst_Log(char *format, ...)
- {
- FILE *logfile = NULL;
- va_list ap;
-
- logfile=fopen(LOG_FILE,"a");
- if(logfile)
- {
- va_start(ap, format);
- vfprintf(logfile, format, ap);
- va_end(ap);
- fclose(logfile);
- }
- }
- //==============================================================================
- //Func: _signal_handler
- //Desc: 处理信号
- //------------------------------------------------------------------------------
- static void _signal_handler(int sig)
- {
- switch(sig)
- {
- case SIGHUP:
- break;
- case SIGTERM:
- Inst_Log("Terminate signal.\n");
- g_Quit = 1;
- break;
- }
- }
复制代码 参考资料:
技术上来说,呆萌、服务、进程都有些什么区别?http://askubuntu.com/questions/1 ... service-and-process
为什么呆萌要运行setsid?http://unix.stackexchange.com/qu ... emonizing-a-process
|
|