Linux下一個簡單守護進程的實現 (Daemon)

來源:互聯網
上載者:User

2012-03-17 wcdj

在Linux/UNIX系統引導的時候會開啟很多服務,這些服務稱為守護進程(也叫Daemon進程)。守護進程是脫離於控制終端並且在後台周期性地執行某種任務或等待處理某些事件的進程,脫離終端是為了避免進程在執行過程中的資訊在任何終端上顯示並且進程也不會被任何終端所產生的中斷資訊所終止。

 

建立守護進程的一般步驟

 

(1) 建立子進程,退出父進程

為了脫離控制終端需要退出父進程,之後的工作都由子進程完成。在Linux中父進程先於子進程退出會造成子進程成為孤兒進程,而每當系統發現一個孤兒進程時,就會自動由1號進程(init)收養它,這樣,原先的子進程就會變成init進程的子進程。

ps –ef | grep ProcName          通過PID/PPID查看進程的父子關係

 

(2) 在子進程中建立新的會話

使用系統函數setsid來完成。

man 2 setsid    查看關於setsid函數的說明

setsid – creates a session and sets theprocess group ID

#include <unistd.h>

pid_t setsid(void);

setsid() creates a new session if thecalling process is not a process group leader. The calling process is theleader of the new session, the process group leader of the new process group,and has no controlling tty. The process group ID and session ID of
the callingprocess are set to the PID of the calling process. The calling process will bethe only process in this new process group and in this new session.

進程組:是一個或多個進程的集合。進程組有進程組ID來唯一標識。除了進程號PID之外,進程組ID也是一個進程的必備屬性。每個進程組都有一個組長進程,其組長進程的進程號等於進程組ID,且該進程組ID不會因組長進程的退出而受到影響。

setsid函數作用:用於建立一個新的會話,並擔任該交談群組的組長。調用setsid有3個作用

(a) 讓進程擺脫原會話的控制;

(b) 讓進程擺脫原進程組的控制;

(c) 讓進程擺脫原控制終端的控制;

使用setsid函數的目的:由於建立守護進程的第一步調用了fork函數來建立子進程再將父進程退出。由於在調用fork函數時,子進程拷貝了父進程的會話期、進程組、控制終端等,雖然父進程退出了,但會話期、進程組、控制終端等並沒有改變,因此,這還不是真正意義上的獨立開了。使用setsid函數後,能夠使進程完全獨立出來,從而擺脫其他進程的控制。

 

(3) 改變目前的目錄為根目錄

使用fork建立的子進程繼承了父進程的當前的工作目錄。由於在進程運行中,目前的目錄所在的檔案系統是不能卸載的,這對以後的使用會造成諸多的麻煩。因此,通常的做法是讓根目錄”/”作為守護進程的當前工作目錄。這樣就可以避免上述的問題。如有特殊的需求,也可以把當前工作目錄換成其他的路徑。改變工作目錄的方法是使用chdir函數。

 

(4) 重設檔案許可權掩碼

檔案許可權掩碼:是指屏蔽掉檔案許可權中的對應位。例如,有個檔案許可權掩碼是050,它就屏蔽了檔案組擁有者的可讀與可執行許可權(對應二進位為,rwx, 101)。由於fork函數建立的子進程繼承了父進程的檔案許可權掩碼,這就給子進程使用檔案帶來了諸多的麻煩。因此,把檔案許可權掩碼設定為0(即,不屏蔽任何許可權),可以增強該守護進程的靈活性。設定檔案許可權掩碼的函數是umask。通常的使用方法為umask(0)。

 

(5) 關閉檔案描述符

用fork建立的子進程也會從父進程那裡繼承一些已經開啟了的檔案。這些被開啟的檔案可能永遠不會被守護進程讀寫,但它們一樣消耗系統資源,而且可能導致所在的檔案系統無法卸載。在使用setsid調用之後,守護進程已經與所屬的控制終端失去了聯絡,因此從終端輸入的字元不可能達到守護進程,守護進程中用常規方法(如printf)輸出的字元也不可能在終端上顯示出來。所以,檔案描述符為0、1、2(即,標準輸入、標準輸出、標準錯誤輸出)的三個檔案已經失去了存在的價值,也應該關閉。

 

(6) 守護進程退出處理

當使用者需要外部停止守護進程時,通常使用kill命令停止該守護進程。所以,守護進程中需要編碼來實現kill發出的signal訊號處理,達到進程正常退出。

 

下面是一個簡單的實現:

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<fcntl.h>// open#include<sys/types.h>#include<sys/stat.h>#include<unistd.h>#include<sys/wait.h>#include<signal.h>#define MAXFILE 65535volatile sig_atomic_t _running = 1;int fd;// signal handlervoid sigterm_handler(int arg){_running = 0;}int main(){pid_t pid;char *buf = "This is a Daemon, wcdj\n";/* 屏蔽一些有關控制終端操作的訊號 * 防止在守護進程沒有正常運轉起來時,因控制終端受到幹擾退出或掛起 * */signal(SIGINT,  SIG_IGN);// 終端終端signal(SIGHUP,  SIG_IGN);// 串連掛斷signal(SIGQUIT, SIG_IGN);// 終端退出signal(SIGPIPE, SIG_IGN);// 向無讀進程的管道寫資料signal(SIGTTOU, SIG_IGN);// 背景程式嘗試寫操作signal(SIGTTIN, SIG_IGN);// 背景程式嘗試讀操作signal(SIGTERM, SIG_IGN);// 終止// test//sleep(20);// try cmd: ./test &; kill -s SIGTERM PID// [1] fork child process and exit father processpid = fork();if(pid < 0){perror("fork error!");exit(1);}else if(pid > 0){exit(0);}// [2] create a new sessionsetsid();// [3] set current pathchar szPath[1024];if(getcwd(szPath, sizeof(szPath)) == NULL){perror("getcwd");exit(1);}else{chdir(szPath);printf("set current path succ [%s]\n", szPath);}// [4] umask 0umask(0);// [5] close useless fdint i;//for (i = 0; i < MAXFILE; ++i)for (i = 3; i < MAXFILE; ++i){close(i);}// [6] set termianl signalsignal(SIGTERM, sigterm_handler);// open file and set rw limitif((fd = open("outfile", O_CREAT|O_WRONLY|O_APPEND, 0600)) < 0){perror("open");exit(1);}printf("\nDaemon begin to work..., and use kill -9 PID to terminate\n");// do sth in loopwhile(_running){if (write(fd, buf, strlen(buf)) != strlen(buf)){perror("write");close(fd);exit(1);}usleep(1000*1000);// 1 s}close(fd);// print dataif((fd = open("outfile", O_RDONLY)) < 0){perror("open");exit(1);}char szBuf[1024] = {0};if(read(fd, szBuf, sizeof(szBuf)) == -1){perror("read");exit(1);}printf("read 1024 bytes:\n%s\n", szBuf);close(fd);return 0;}/*   gcc -Wall -g -o test test.c   ps ux | grep -v grep | grep test   tail -f outfile   kill -s SIGTERM PID */

參考:

[1] 守護進程
[2]
編寫Linux/Unix守護進程
[3] Linux 訊號signal處理函數
[4]
The usage of sig_atomic_t in linux signal mask function

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.