嵌入式linux系统下简单守护进程(daemon)的编写
最近公司項目需要,需要在我們的嵌入式linux設備中創建一個守護進程,用于保護系統中的主進程,防止某些不可預期的意外導致主進程異常結束后,系統完全宕機沒有任何反應,破壞用戶體驗感。但是,查閱諸多資料之后發現,大部分人都只講述了如何在x86平臺上創建和實現守護進程,而并沒有人介紹過如何在嵌入式平臺上創建和實現守護進程。于是,經過一番摸索之后,從原理到代碼,都進行了一些大致的了解,我自己提出了一些想法。下面就進行一下簡單的總結和整理。
1、技術原理
下面是網上摘抄的,關于x86的linux系統中對于守護進程的介紹和描述。
守護進程(Daemon)是一種運行在后臺的一種特殊的進程,它獨立于控制終端并且周期性的執行某種任務或等待處理某些發生的事件。
守護進程是個特殊的孤兒進程,這種進程脫離終端,為什么要脫離終端呢?之所以脫離于終端是為了避免進程被任何終端所產生的信息所打斷,其在執行過程中的信息也不在任何終端上顯示。由于在 Linux 中,每一個系統與用戶進行交流的界面稱為終端,每一個從此終端開始運行的進程都會依附于這個終端,這個終端就稱為這些進程的控制終端,當控制終端被關閉時,相應的進程都會自動關閉。但是守護進程卻能突破這種限制,它脫離于終端并且在后臺運行,并且它脫離終端的目的是為了避免進程在運行的過程中的信息在任何終端中顯示并且進程也不會被任何終端所產生的終端信息所打斷。它從被執行的時候開始運轉,知道整個系統關閉才退出(當然可以認為的殺死相應的守護進程)。如果想讓某個進程不因為用戶或中斷或其他變化而影響,那么就必須把這個進程變成一個守護進程。
2、設計步驟
對于x86平臺的linux系統,理論上來說,要想實現上述的效果,守護進程具有一套嚴格的實現步驟。也就是說,守護進程必須在啟動伊始,就去除掉一些系統相關的限制,這樣才能穩定的在后臺運行,而不至于被其他任務所干擾和影響。
下面是在x86平臺編寫守護進程的基本過程:
-
下面就是摘自某前輩的博客上的全套源碼:
3、實際情況
從上面的流程邏輯和實際代碼可以看出,x86平臺的守護進程,其實還是比較復雜的,需要進行一堆比較繁瑣的初始化過程。然而,對于嵌入式平臺而言,流程似乎可以簡化一些,不用這么復雜的處理。因為,在本次嵌入式系統中啟用守護進程。其目的只是簡單的利用這個守護進程來啟動另一個被守護的進程,然后定時監控該進程是否仍在正常運行,一旦發現其運行異常,則立即重啟該進程就好。
所以,我對上述的流程進行了簡化,得到如下的流程:
-
4、實際源碼
以下就是在本嵌入式系統項目中所設計的守護進程模塊的全套代碼。
/************************************************************************************************** ** 函數名稱: lockfile ** 功能描述: 對文件加鎖/解鎖 ** 輸入參數: lock: 1表示進行加鎖處理,0表示進行解鎖處理 ** 輸出參數: 無 ** 返回參數: 無 **************************************************************************************************/ int tryto_lockfile(int fd, int lock) {struct flock fl;fl.l_type = (lock == 1) ? F_WRLCK : F_UNLCK;fl.l_start = 0;fl.l_whence = SEEK_SET;fl.l_len = 0;return (fcntl(fd, F_SETLK, &fl)); }/************************************************************************************************** ** 函數名稱: get_proc_running_state ** 功能描述: 獲取進程運行狀態 ** 輸入參數: 無 ** 輸出參數: 無 ** 返回參數: 返回-1表示路徑錯誤 ** 返回參數: 返回0表示進程從未運行過,返回1表示進程曾經運行過但是現在停止運行了,返回2表示進程正在運行中 **************************************************************************************************/ static int get_proc_running_state(const char* filename) {int fd;if (filename == NULL) { /* 文件名為空 */return -1;}fd = open(filename, O_RDWR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));if (fd < 0) { /* 文件不存在,表示進程從未運行過 */return 0;}if (tryto_lockfile(fd, 1) == -1) { /* 文件加鎖失敗,表示進程在運行中 */close(fd);return 2;} else { /* 文件加鎖成功,表示進程已經消失 */tryto_lockfile(fd, 0); /* 此處要注意記得解鎖和關閉文件 */close(fd);return 1;} }/************************************************************************************************** ** 函數名稱: proc_watch ** 功能描述: 檢測進程是否有在運行,沒有運行則重新啟動之 ** 輸入參數: procname: 進程名 ** 輸出參數: 無 ** 返回參數: 返回-1表示進程從未運行過;返回0表示進程當前運行正常; ** 返回參數: 返回其他非零值表示進程不存在且已被重新啟動,返回的值是新的pid值 **************************************************************************************************/ int proc_watch(const char *procname) {int result, state;char filename[100];result = 0;sprintf(filename, "/var/run/%s.pid", procname);state = get_proc_running_state(filename);switch (state){case 0:result = -1;break;case 1:result = start_proc_by_name(procname);break;case 2:result = 0;break;default:break;}return result; }/************************************************************************************************** ** 函數名稱: start_proc ** 功能描述: 啟動進程開始運行 ** 輸入參數: 無 ** 輸出參數: 無 ** 返回參數: 進程的ID號,若啟動失敗則返回0 **************************************************************************************************/ int start_proc_by_name(const char* procname) {pid_t pid, child_pid;char filename[100];sprintf(filename, "%s%s", PROC_FILE_PATH, procname);child_pid = 0;if (access(filename, X_OK | F_OK) != 0) { /* 如果文件存在,并且可執行 */return 0;}pid = fork(); /* 首先要fork一個進程出來 */if (pid < 0) { /* 創建進程失敗 */return 0;} else if (pid == 0) { /* 創建進程成功,此處是子進程的代碼 */if (execl(filename, procname, (char *)NULL) != -1) {return 1;} else {return 0;}} else { /* 創建進程成功,此處是父進程代碼 */child_pid = pid;}return (int)child_pid; }/************************************************************************************************** ** 函數名稱: thread_client_hdl ** 功能描述: client進程監視線程 ** 輸入參數: 無 ** 輸出參數: 無 ** 返回參數: 無 **************************************************************************************************/ static void *thread_client_hdl(void *pdata) {int result;pdata = pdata;sleep(10); /* 第一次要進行延時 */for (;;) {printf("time to check thread_client...\n");result = proc_watch(PROC_NAME_CLIENT);if (result == -1) {printf("thread_client never exist...\n");} else if (result == 0) {printf("thread_client running ok...\n");} else {printf("thread_client has gone! but restarted...\n");}sleep(10);}return NULL; }/************************************************************************************************** ** 函數名稱: main ** 功能描述: 入口主函數 ** 輸入參數: 無 ** 輸出參數: 無 ** 返回參數: 無 **************************************************************************************************/ int main(int argc, char *argv[]) {int client_para;char *p, *process_name;pthread_t thread_client;process_name = argv[0]; /* 獲取進程名稱 */p = process_name + strlen(process_name);while (*p != '/' && p != process_name) {p--;}if (*p == '/') {process_name = p + 1;}printf("\"%s\" starting...\n", process_name);client_para = 0x01;if (pthread_create(&thread_client, NULL, thread_client_hdl, &client_para) != 0) {printf("create thread_client failed!\n");return 1;}if (start_proc_by_name(PROC_NAME_CLIENT) == 0) {printf("start thread_client failed!\n");return 1;}for (;;) {sleep(60);printf("i am still alive...\n");}return 0; }5、其他說明
待補充
6、參考文獻
1、http://blog.csdn.net/lianghe_work/article/details/47659889
2、http://blog.csdn.net/liangxanhai/article/details/7752898
總結
以上是生活随笔為你收集整理的嵌入式linux系统下简单守护进程(daemon)的编写的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一些世界上著名杀软的专杀工具下载地址
- 下一篇: QQ浏览器谷歌版吾爱破解(QQ浏览器最新