日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

嵌入式linux系统下简单守护进程(daemon)的编写

發布時間:2023/12/15 linux 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 嵌入式linux系统下简单守护进程(daemon)的编写 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近公司項目需要,需要在我們的嵌入式linux設備中創建一個守護進程,用于保護系統中的主進程,防止某些不可預期的意外導致主進程異常結束后,系統完全宕機沒有任何反應,破壞用戶體驗感。但是,查閱諸多資料之后發現,大部分人都只講述了如何在x86平臺上創建和實現守護進程,而并沒有人介紹過如何在嵌入式平臺上創建和實現守護進程。于是,經過一番摸索之后,從原理到代碼,都進行了一些大致的了解,我自己提出了一些想法。下面就進行一下簡單的總結和整理。

1、技術原理

下面是網上摘抄的,關于x86的linux系統中對于守護進程的介紹和描述。

守護進程(Daemon)是一種運行在后臺的一種特殊的進程,它獨立于控制終端并且周期性的執行某種任務或等待處理某些發生的事件。

守護進程是個特殊的孤兒進程,這種進程脫離終端,為什么要脫離終端呢?之所以脫離于終端是為了避免進程被任何終端所產生的信息所打斷,其在執行過程中的信息也不在任何終端上顯示。由于在 Linux 中,每一個系統與用戶進行交流的界面稱為終端,每一個從此終端開始運行的進程都會依附于這個終端,這個終端就稱為這些進程的控制終端,當控制終端被關閉時,相應的進程都會自動關閉。但是守護進程卻能突破這種限制,它脫離于終端并且在后臺運行,并且它脫離終端的目的是為了避免進程在運行的過程中的信息在任何終端中顯示并且進程也不會被任何終端所產生的終端信息所打斷。它從被執行的時候開始運轉,知道整個系統關閉才退出(當然可以認為的殺死相應的守護進程)。如果想讓某個進程不因為用戶或中斷或其他變化而影響,那么就必須把這個進程變成一個守護進程。

2、設計步驟

對于x86平臺的linux系統,理論上來說,要想實現上述的效果,守護進程具有一套嚴格的實現步驟。也就是說,守護進程必須在啟動伊始,就去除掉一些系統相關的限制,這樣才能穩定的在后臺運行,而不至于被其他任務所干擾和影響。

下面是在x86平臺編寫守護進程的基本過程:

  • 屏蔽一些控制終端操作的信號。這是為了防止守護進行在沒有運行起來前,控制終端受到干擾退出或掛起。關于信號的更詳細用法,請看《信號中斷處理》。
  • 在后臺運行。這是為避免掛起控制終端將守護進程放入后臺執行。方法是在進程中調用 fork() 使父進程終止, 讓守護進行在子進程中后臺執行。
  • 脫離控制終端、登錄會話和進程組。有必要先介紹一下 Linux 中的進程與控制終端,登錄會話和進程組之間的關系:進程屬于一個進程組,進程組號(GID)就是進程組長的進程號(PID)。登錄會話可以包含多個進程組。這些進程組共享一個控制終端。這個控制終端通常是創建進程的 shell 登錄終端。 控制終端、登錄會話和進程組通常是從父進程繼承下來的。我們的目的就是要擺脫它們 ,使之不受它們的影響。因此需要調用 setsid() 使子進程成為新的會話組長。setsid() 調用成功后,進程成為新的會話組長和新的進程組長,并與原來的登錄會話和進程組脫離。由于會話過程對控制終端的獨占性,進程同時與控制終端脫離。
  • 禁止進程重新打開控制終端。現在,進程已經成為無終端的會話組長,但它可以重新申請打開一個控制終端。可以通過使進程不再成為會話組長來禁止進程重新打開控制終端,采用的方法是再次創建一個子進程。
  • 關閉打開的文件描述符。進程從創建它的父進程那里繼承了打開的文件描述符。如不關閉,將會浪費系統資源,造成進程所在的文件系統無法卸下以及引起無法預料的錯誤。
  • 改變當前工作目錄。進程活動時,其工作目錄所在的文件系統不能卸下。一般需要將工作目錄改變到根目錄。對于需要轉儲核心,寫運行日志的進程將工作目錄改變到特定目錄如 /tmp。
  • 重設文件創建掩模。進程從創建它的父進程那里繼承了文件創建掩模。它可能修改守護進程所創建的文件的存取權限。為防止這一點,必須將文件創建掩模清除。
  • 處理 SIGCHLD 信號。對于某些進程,特別是服務器進程往往在請求到來時生成子進程處理請求。如果父進程不等待子進程結束,子進程將成為僵尸進程(zombie)從而占用系統資源(關于僵尸進程的更多詳情,請看《僵尸進程》)。如果父進程等待子進程結束,將增加父進程的負擔,影響服務器進程的并發性能。在 Linux 下可以簡單地將 SIGCHLD 信號的操作設為 SIG_IGN 。這樣,內核在子進程結束時才不會產生僵尸進程。
  • -
    下面就是摘自某前輩的博客上的全套源碼:

    #include <unistd.h> #include <signal.h> #include <fcntl.h> #include <sys/syslog.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <time.h> int init_daemon(void) { int pid; int i; // 1)屏蔽一些控制終端操作的信號 signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGTSTP,SIG_IGN); signal(SIGHUP ,SIG_IGN); // 2)在后臺運行 if( pid=fork() ){// 父進程 exit(0);//結束父進程,子進程繼續 }else if(pid< 0){// 出錯 perror("fork"); exit(EXIT_FAILURE); } // 3)脫離控制終端、登錄會話和進程組 setsid(); // 4)禁止進程重新打開控制終端 if( pid=fork() ){// 父進程 exit(0);// 結束第一子進程,第二子進程繼續(第二子進程不再是會話組長) }else if(pid< 0){// 出錯 perror("fork"); exit(EXIT_FAILURE); } // 5)關閉打開的文件描述符 // NOFILE 為 <sys/param.h> 的宏定義 // NOFILE 為文件描述符最大個數,不同系統有不同限制 for(i=0; i< NOFILE; ++i){ close(i); } // 6)改變當前工作目錄 chdir("/tmp"); // 7)重設文件創建掩模 umask(0); // 8)處理 SIGCHLD 信號 signal(SIGCHLD,SIG_IGN); return 0; } int main(int argc, char *argv[]) { init_daemon(); while(1); return 0; }

    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)的编写的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧洲做受高潮免费看 | 亚洲欧美校园春色 | 在线一区二区三区 | jizzz18| 一级视频在线播放 | 精品国产一区二区三区四 | 奇米精品一区二区三区在线观看 | 精品九九九九 | 欧美日韩亚洲精品一区二区 | 欧美巨乳美女 | 夜色视频网 | 七月婷婷综合 | 欧美激情一区二区三区在线 | 国产精品久久久久久久久久久久 | 色婷婷综合久久久久中文字幕 | 久久人人爽人人爽人人 | 免费看成人毛片 | 天堂av免费在线观看 | 真实乱视频国产免费观看 | 这里只有精品66 | 欧美亚洲另类小说 | 污污视频免费网站 | 婷婷色网站 | 久久综合伊人77777麻豆 | 亚洲一区二区动漫 | 免费看v片 | 人妻少妇精品无码专区 | 国产的av | 伊人久久免费视频 | 欧美日本| 国产熟妇乱xxxxx大屁股网 | 久久av网址| 欧美又粗又大xxxxbbbb疯狂 | 亚洲午夜一区二区 | 人妻精品久久久久中文字幕69 | 日本网站在线 | 娇妻玩4p被三个男人伺候电影 | 日韩一级片av | 亚洲精品一区二区潘金莲 | 国产第九页 | 国产成人三级在线播放 | 日韩免费av片 | 亚洲精品黄色 | 自拍偷拍在线播放 | 亚洲精品字幕在线 | 污污免费视频 | 日本一区二区高清免费 | h视频免费在线观看 | 伊人精品一区二区三区 | 麻豆视频免费入口 | 国产精品一线二线三线 | 日本福利一区二区 | 天天欲色 | 亚洲精品中文字幕在线 | 成人在线精品视频 | 一区二区免费看 | 久久色中文字幕 | 久久发布国产伦子伦精品 | 欧美xxxxxx片免费播放软件 | 樱花视频在线观看 | 亚洲国产精品视频在线观看 | 色婷婷香蕉在线一区二区 | av中文资源网 | 我爱52av | 一级性生活免费视频 | 99re这里只有精品在线观看 | 欧美一区二区三区久久久 | 国产中文字幕在线免费观看 | 国产日韩视频 | 亚洲午夜毛片 | 欧美成人一二区 | 黄色一级片在线播放 | 久久这里只有精品8 | 91快色 | 天天色天天爱 | 亚欧中文字幕 | 天堂网一区二区三区 | 国产精品免费一区二区区 | h片在线观看| 国产精品国产三级国产aⅴ9色 | 一级片视频在线观看 | 久久综合九九 | 天堂亚洲网 | 免费看日韩毛片 | 日韩欧美成人精品 | 欧美一区二区三区四区视频 | 久久性视频 | av爱爱| 女性向小h片资源在线观看 日本天天操 | 日韩中文字幕有码 | 97人人草| 四虎激情 | 长篇h版少妇沉沦交换 | 亚洲国产精品一区 | 香蕉视频网页版 | 99久热| 人人看人人爱 | 成人91网站 | 岛国一区二区三区 |