嵌入式linux系统下简单守护进程(daemon)的编写
最近公司項(xiàng)目需要,需要在我們的嵌入式linux設(shè)備中創(chuàng)建一個(gè)守護(hù)進(jìn)程,用于保護(hù)系統(tǒng)中的主進(jìn)程,防止某些不可預(yù)期的意外導(dǎo)致主進(jìn)程異常結(jié)束后,系統(tǒng)完全宕機(jī)沒(méi)有任何反應(yīng),破壞用戶體驗(yàn)感。但是,查閱諸多資料之后發(fā)現(xiàn),大部分人都只講述了如何在x86平臺(tái)上創(chuàng)建和實(shí)現(xiàn)守護(hù)進(jìn)程,而并沒(méi)有人介紹過(guò)如何在嵌入式平臺(tái)上創(chuàng)建和實(shí)現(xiàn)守護(hù)進(jìn)程。于是,經(jīng)過(guò)一番摸索之后,從原理到代碼,都進(jìn)行了一些大致的了解,我自己提出了一些想法。下面就進(jìn)行一下簡(jiǎn)單的總結(jié)和整理。
1、技術(shù)原理
下面是網(wǎng)上摘抄的,關(guān)于x86的linux系統(tǒng)中對(duì)于守護(hù)進(jìn)程的介紹和描述。
守護(hù)進(jìn)程(Daemon)是一種運(yùn)行在后臺(tái)的一種特殊的進(jìn)程,它獨(dú)立于控制終端并且周期性的執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。
守護(hù)進(jìn)程是個(gè)特殊的孤兒進(jìn)程,這種進(jìn)程脫離終端,為什么要脫離終端呢?之所以脫離于終端是為了避免進(jìn)程被任何終端所產(chǎn)生的信息所打斷,其在執(zhí)行過(guò)程中的信息也不在任何終端上顯示。由于在 Linux 中,每一個(gè)系統(tǒng)與用戶進(jìn)行交流的界面稱(chēng)為終端,每一個(gè)從此終端開(kāi)始運(yùn)行的進(jìn)程都會(huì)依附于這個(gè)終端,這個(gè)終端就稱(chēng)為這些進(jìn)程的控制終端,當(dāng)控制終端被關(guān)閉時(shí),相應(yīng)的進(jìn)程都會(huì)自動(dòng)關(guān)閉。但是守護(hù)進(jìn)程卻能突破這種限制,它脫離于終端并且在后臺(tái)運(yùn)行,并且它脫離終端的目的是為了避免進(jìn)程在運(yùn)行的過(guò)程中的信息在任何終端中顯示并且進(jìn)程也不會(huì)被任何終端所產(chǎn)生的終端信息所打斷。它從被執(zhí)行的時(shí)候開(kāi)始運(yùn)轉(zhuǎn),知道整個(gè)系統(tǒng)關(guān)閉才退出(當(dāng)然可以認(rèn)為的殺死相應(yīng)的守護(hù)進(jìn)程)。如果想讓某個(gè)進(jìn)程不因?yàn)橛脩艋蛑袛嗷蚱渌兓绊?#xff0c;那么就必須把這個(gè)進(jìn)程變成一個(gè)守護(hù)進(jìn)程。
2、設(shè)計(jì)步驟
對(duì)于x86平臺(tái)的linux系統(tǒng),理論上來(lái)說(shuō),要想實(shí)現(xiàn)上述的效果,守護(hù)進(jìn)程具有一套嚴(yán)格的實(shí)現(xiàn)步驟。也就是說(shuō),守護(hù)進(jìn)程必須在啟動(dòng)伊始,就去除掉一些系統(tǒng)相關(guān)的限制,這樣才能穩(wěn)定的在后臺(tái)運(yùn)行,而不至于被其他任務(wù)所干擾和影響。
下面是在x86平臺(tái)編寫(xiě)守護(hù)進(jìn)程的基本過(guò)程:
-
下面就是摘自某前輩的博客上的全套源碼:
3、實(shí)際情況
從上面的流程邏輯和實(shí)際代碼可以看出,x86平臺(tái)的守護(hù)進(jìn)程,其實(shí)還是比較復(fù)雜的,需要進(jìn)行一堆比較繁瑣的初始化過(guò)程。然而,對(duì)于嵌入式平臺(tái)而言,流程似乎可以簡(jiǎn)化一些,不用這么復(fù)雜的處理。因?yàn)?#xff0c;在本次嵌入式系統(tǒng)中啟用守護(hù)進(jìn)程。其目的只是簡(jiǎn)單的利用這個(gè)守護(hù)進(jìn)程來(lái)啟動(dòng)另一個(gè)被守護(hù)的進(jìn)程,然后定時(shí)監(jiān)控該進(jìn)程是否仍在正常運(yùn)行,一旦發(fā)現(xiàn)其運(yùn)行異常,則立即重啟該進(jìn)程就好。
所以,我對(duì)上述的流程進(jìn)行了簡(jiǎn)化,得到如下的流程:
-
4、實(shí)際源碼
以下就是在本嵌入式系統(tǒng)項(xiàng)目中所設(shè)計(jì)的守護(hù)進(jìn)程模塊的全套代碼。
/************************************************************************************************** ** 函數(shù)名稱(chēng): lockfile ** 功能描述: 對(duì)文件加鎖/解鎖 ** 輸入?yún)?shù): lock: 1表示進(jìn)行加鎖處理,0表示進(jìn)行解鎖處理 ** 輸出參數(shù): 無(wú) ** 返回參數(shù): 無(wú) **************************************************************************************************/ 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)); }/************************************************************************************************** ** 函數(shù)名稱(chēng): get_proc_running_state ** 功能描述: 獲取進(jìn)程運(yùn)行狀態(tài) ** 輸入?yún)?shù): 無(wú) ** 輸出參數(shù): 無(wú) ** 返回參數(shù): 返回-1表示路徑錯(cuò)誤 ** 返回參數(shù): 返回0表示進(jìn)程從未運(yùn)行過(guò),返回1表示進(jìn)程曾經(jīng)運(yùn)行過(guò)但是現(xiàn)在停止運(yùn)行了,返回2表示進(jìn)程正在運(yùn)行中 **************************************************************************************************/ 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) { /* 文件不存在,表示進(jìn)程從未運(yùn)行過(guò) */return 0;}if (tryto_lockfile(fd, 1) == -1) { /* 文件加鎖失敗,表示進(jìn)程在運(yùn)行中 */close(fd);return 2;} else { /* 文件加鎖成功,表示進(jìn)程已經(jīng)消失 */tryto_lockfile(fd, 0); /* 此處要注意記得解鎖和關(guān)閉文件 */close(fd);return 1;} }/************************************************************************************************** ** 函數(shù)名稱(chēng): proc_watch ** 功能描述: 檢測(cè)進(jìn)程是否有在運(yùn)行,沒(méi)有運(yùn)行則重新啟動(dòng)之 ** 輸入?yún)?shù): procname: 進(jìn)程名 ** 輸出參數(shù): 無(wú) ** 返回參數(shù): 返回-1表示進(jìn)程從未運(yùn)行過(guò);返回0表示進(jìn)程當(dāng)前運(yùn)行正常; ** 返回參數(shù): 返回其他非零值表示進(jìn)程不存在且已被重新啟動(dòng),返回的值是新的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; }/************************************************************************************************** ** 函數(shù)名稱(chēng): start_proc ** 功能描述: 啟動(dòng)進(jìn)程開(kāi)始運(yùn)行 ** 輸入?yún)?shù): 無(wú) ** 輸出參數(shù): 無(wú) ** 返回參數(shù): 進(jìn)程的ID號(hào),若啟動(dòng)失敗則返回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) { /* 如果文件存在,并且可執(zhí)行 */return 0;}pid = fork(); /* 首先要fork一個(gè)進(jìn)程出來(lái) */if (pid < 0) { /* 創(chuàng)建進(jìn)程失敗 */return 0;} else if (pid == 0) { /* 創(chuàng)建進(jìn)程成功,此處是子進(jìn)程的代碼 */if (execl(filename, procname, (char *)NULL) != -1) {return 1;} else {return 0;}} else { /* 創(chuàng)建進(jìn)程成功,此處是父進(jìn)程代碼 */child_pid = pid;}return (int)child_pid; }/************************************************************************************************** ** 函數(shù)名稱(chēng): thread_client_hdl ** 功能描述: client進(jìn)程監(jiān)視線程 ** 輸入?yún)?shù): 無(wú) ** 輸出參數(shù): 無(wú) ** 返回參數(shù): 無(wú) **************************************************************************************************/ static void *thread_client_hdl(void *pdata) {int result;pdata = pdata;sleep(10); /* 第一次要進(jìn)行延時(shí) */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; }/************************************************************************************************** ** 函數(shù)名稱(chēng): main ** 功能描述: 入口主函數(shù) ** 輸入?yún)?shù): 無(wú) ** 輸出參數(shù): 無(wú) ** 返回參數(shù): 無(wú) **************************************************************************************************/ int main(int argc, char *argv[]) {int client_para;char *p, *process_name;pthread_t thread_client;process_name = argv[0]; /* 獲取進(jìn)程名稱(chēng) */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、其他說(shuō)明
待補(bǔ)充
6、參考文獻(xiàn)
1、http://blog.csdn.net/lianghe_work/article/details/47659889
2、http://blog.csdn.net/liangxanhai/article/details/7752898
總結(jié)
以上是生活随笔為你收集整理的嵌入式linux系统下简单守护进程(daemon)的编写的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一些世界上著名杀软的专杀工具下载地址
- 下一篇: linux下如何在shell中结束进程(