Linux daemon進(jìn)程的應(yīng)用、實現(xiàn)和原理
來源:程序員人生 發(fā)布時間:2015-05-05 08:26:52 閱讀次數(shù):3625次
甚么情況下用daemon進(jìn)程
生產(chǎn)環(huán)境下,除我們ssh登錄上去,然后手動跑的那部份之外,其他都是自動運行的,這些大部份都應(yīng)當(dāng)是后臺履行的。如何才能后臺履行呢?
- nohup
./XXX &
- 由系統(tǒng)的其他daemon進(jìn)程啟動。這樣的話,你的程序是它的子進(jìn)程,跟終端沒關(guān)系。退出終端也不會致使進(jìn)程退出。如寫在crontab里。
- 寫成daemon程序,可以手動履行,退出終端時程序不退出。
如何選擇呢?
(1)首先,清算過期日志這1類需求,可以寫1個死循環(huán)1直運行,也能夠?qū)懺赾rontab里,每次履行完就退出(如果每分鐘1次可以滿足的話);
(2)crontab的需要接受最多1分鐘的時延,如果實時性要求更高1些,那末就需要斟酌寫個死循環(huán)了,這個程序可以由crontab來start和restart,只有在掛了重啟時才會出現(xiàn)1分鐘時延;
* * * * * /usr/bin/flock -nx /home/chenming/lock/test1.lock -c '/home/chenming/test1 >/dev/null 2>&1'
(3)服務(wù)不能中斷的(nginx、redis、apache,所有在線服務(wù)),1般都是daemon程序。但理論上用(2)似乎也能夠;固然這二者細(xì)節(jié)上有很多區(qū)分。
怎樣用daemon進(jìn)程
linux
C/C++可以直接調(diào)用int daemon(int, int)函數(shù),不需要自己重新實現(xiàn)。示例代碼:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Usage: $0 no_ch_dir no_close_fd
");
exit(0);
}
int no_ch_dir = atoi(argv[1]);
int no_close_fd = atoi(argv[2]);
std::cout << "main pid : " << getpid() << std::endl;
std::cout << "main parent pid : " << getppid() << std::endl;
std::cout << "main pwd : " << get_current_dir_name() << std::endl;
if (daemon(no_ch_dir, no_close_fd) != 0) {
// 1般都用daemon(0,0)
// 成功返回0,失敗返回⑴
// daemon(0,0):chdir到/,關(guān)閉0,1,2描寫符。
std::cout << "stdout: daemon = ⑴" << std::endl;
std::cerr << "stderr: daemon = ⑴" << std::endl;
return 1;
}
std::cout << "stdout: daemon = 0" << std::endl;
std::cerr << "stderr: daemon = 0" << std::endl;
std::cout << "sub pid : " << getpid() << std::endl;
std::cout << "sub parent pid : " << getppid() << std::endl;
std::cout << "sub pwd : " << get_current_dir_name() << std::endl;
while (1);
return 0;
}
編譯運行:
[chenming@localhost ~]$ g++ test1.cc -o test1
[chenming@localhost ~]$ ./test1 0 0
main pid : 7978
main parent pid : 1382
main pwd : /home/chenming
[chenming@localhost ~]$ ps -ef | grep test1
94:chenming 7864 7573 0 16:09 pts/0 00:00:16 vim test1.cc
95:chenming 7897 1 97 16:14 ? 00:33:07 ./test1 0 0
97:chenming 7979 1 47 16:48 ? 00:00:04 ./test1 0 0
99:chenming 7981 1382 8 16:49 pts/1 00:00:00 grep -inE --color test1
[chenming@localhost ~]$ ll /proc/7979/fd
total 0
lrwx------. 1 chenming chenming 64 May 1 16:49 0 -> /dev/null
lrwx------. 1 chenming chenming 64 May 1 16:49 1 -> /dev/null
lrwx------. 1 chenming chenming 64 May 1 16:49 2 -> /dev/null
[chenming@localhost ~]$ lsof -p 7979
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
test1 7979 chenming cwd DIR 253,0 4096 2 /
test1 7979 chenming rtd DIR 253,0 4096 2 /
test1 7979 chenming txt REG 253,0 8355 142259 /home/chenming/test1
test1 7979 chenming mem REG 253,0 122232 52742 /lib/libgcc_s⑷.4.7⑵0120601.so.1
test1 7979 chenming mem REG 253,0 142600 38788 /lib/ld⑵.12.so
test1 7979 chenming mem REG 253,0 1906308 38865 /lib/libc⑵.12.so
test1 7979 chenming mem REG 253,0 202040 47921 /lib/libm⑵.12.so
test1 7979 chenming mem REG 253,0 942040 52866 /usr/lib/libstdc++.so.6.0.13
test1 7979 chenming 0u CHR 1,3 0t0 3903 /dev/null
test1 7979 chenming 1u CHR 1,3 0t0 3903 /dev/null
test1 7979 chenming 2u CHR 1,3 0t0 3903 /dev/null
man
3 daemon可以查看到函數(shù)簽名:
#include
<unistd.h>
int
daemon(int nochdir, int noclose);
怎樣寫daemon進(jìn)程
1.fork,父進(jìn)程退出
2.setsid。跟終端脫離關(guān)系。
3.umask、關(guān)掉0,1,2文件描寫符。
4.chdir
5.信號處理
這里只有1和
2是必須的。31般都會做;5大部份不做。
自己實現(xiàn)1個:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
int daem(int no_ch_dir, int no_close_fd) {
int pid = fork();
if (pid < 0) {
return ⑴;
}else if (pid > 0){
exit(0);
}
if (setsid() < 0) {
return ⑴;
}
if (no_ch_dir == 0) {
chdir("/");
}
umask(0);
if (no_close_fd == 0) {
close(0);
close(1);
close(2);
}
return 0;
}
redis的實現(xiàn):
void daemonize(void) {
int fd;
if (fork() != 0) exit(0); /* parent exits */
setsid(); /* create a new session */
/* Every output goes to /dev/null. If Redis is daemonized but
* the 'logfile' is set to 'stdout' in the configuration file
* it will not log at all. */
if ((fd = open("/dev/null", O_RDWR, 0)) != ⑴) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO) close(fd);
}
}
memcached的實現(xiàn):
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "memcached.h"
int daemonize(int nochdir, int noclose)
{
int fd;
switch (fork()) {
case ⑴:
return (⑴);
case 0:
break;
default:
_exit(EXIT_SUCCESS);
}
if (setsid() == ⑴)
return (⑴);
if (nochdir == 0) {
if(chdir("/") != 0) {
perror("chdir");
return (⑴);
}
}
if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != ⑴) {
if(dup2(fd, STDIN_FILENO) < 0) {
perror("dup2 stdin");
return (⑴);
}
if(dup2(fd, STDOUT_FILENO) < 0) {
perror("dup2 stdout");
return (⑴);
}
if(dup2(fd, STDERR_FILENO) < 0) {
perror("dup2 stderr");
return (⑴);
}
if (fd > STDERR_FILENO) {
if(close(fd) < 0) {
perror("close");
return (⑴);
}
}
}
return (0);
}
nginx的實現(xiàn):
#include <ngx_config.h>
#include <ngx_core.h>
ngx_int_t
ngx_daemon(ngx_log_t *log)
{
int fd;
switch (fork()) {
case ⑴:
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
return NGX_ERROR;
case 0:
break;
default:
exit(0);
}
ngx_pid = ngx_getpid();
if (setsid() == ⑴) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
return NGX_ERROR;
}
umask(0);
fd = open("/dev/null", O_RDWR);
if (fd == ⑴) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
"open("/dev/null") failed");
return NGX_ERROR;
}
if (dup2(fd, STDIN_FILENO) == ⑴) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
return NGX_ERROR;
}
if (dup2(fd, STDOUT_FILENO) == ⑴) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
return NGX_ERROR;
}
#if 0
if (dup2(fd, STDERR_FILENO) == ⑴) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
return NGX_ERROR;
}
#endif
if (fd > STDERR_FILENO) {
if (close(fd) == ⑴) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
return NGX_ERROR;
}
}
return NGX_OK;
}
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈