Linux 下的守護程式:如何撰寫並使用簡單的守護程式
守護程式是 Linux 系統中一種特殊的進程,它是在背景運行的,沒有控制終端,不受使用者的干擾,負責執行一些系統或應用相關的任務和功能。守護程式的作用是提高系統的穩定性和效率,以應對一些不可預期的意外或異常。在嵌入式 Linux 設備中,守護程序可以用來保護系統中的主進程,防止其異常結束後,導致系統完全宕機,破壞使用者體驗。但是,你真的了解 Linux 下的守護程式嗎?你知道如何在 Linux 下編寫和使用簡單的守護程式嗎?本文將為你詳細介紹 Linux 下的守護程序的相關知識,讓你在 Linux 下更好地使用和理解這個強大的進程類型。
#式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 #include #include #include #include #include #include #include #include #include int init_daemon(void) { int pid; int i; // 1)屏蔽一些控制终端操作的信 号 signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGTSTP,SIG_IGN); signal(SIGHU P ,SIG_IGN); // 2)在后台运行 if( pid=fork() ){// 父进程 exit(0);//结束父进程,子进程继 续 }else if(pid 的宏定义 // NOFILE 为文件描述符最大个数,不同系统有不同限 制 for(i=0; i
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 (f cntl(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)); i f (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 fi lename[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 = sta rt_proc_by_name(procname); break; case 2: result = 0; break; default: break; } return resu lt; } /************************************************************************************ ************** ** 函数名称: start_proc ** 功能描述: 启动进程开始运行 ** 输入参数: 无 ** 输出参 数: 无 ** 返回参数: 进程的ID号,若启动失败则返回 0 ***************************************************************************************** *********/ int start_proc_by_name(const char* procname) { pid_t pid, child_pid; char filen ame[100]; sprintf(filename, "%s%s", PROC_FILE_PATH, procname); child_pid = 0; if (access(f ilename, 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 { /* 创建进程成功,此处是父进程代 ******************************************************************* ** 函数名 称: thread_client_hdl ** 功能描述: client进程监视线程 ** 输入参数: 无 ** 输出参数: 无 ** 返回参 数: 无 ************************************************************************************* *************/ static void *thread_client_hdl(void *pdata) { int result; pdata = pdata; sl eep(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; }
通过本文,你应该对 Linux 下的守护进程有了一个基本的了解,知道了它的定义、特点和用途。你也应该明白了如何在 Linux 下编写和使用简单的守护进程,以及使用守护进程时需要注意的一些问题和技巧。我们建议你在使用 Linux 系统时,使用守护进程来提高系统的稳定性和效率。同时,我们也提醒你在使用守护进程时要注意一些潜在的问题和挑战,如信号处理、日志记录、资源管理等。希望本文能够帮助你更好地使用 Linux 系统,让你在 Linux 下掌握守护进程的编写和使用。
以上是Linux 下的守護程式:如何撰寫並使用簡單的守護程式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

學習Linux並不難。 1.Linux是一個開源操作系統,基於Unix,廣泛應用於服務器、嵌入式系統和個人電腦。 2.理解文件系統和權限管理是關鍵,文件系統是層次化的,權限包括讀、寫和執行。 3.包管理系統如apt和dnf使得軟件管理方便。 4.進程管理通過ps和top命令實現。 5.從基本命令如mkdir、cd、touch和nano開始學習,再嘗試高級用法如shell腳本和文本處理。 6.常見錯誤如權限問題可以通過sudo和chmod解決。 7.性能優化建議包括使用htop監控資源、清理不必要文件和使用sy

Linux管理員的平均年薪在美國為75,000至95,000美元,歐洲為40,000至60,000歐元。提升薪資可以通過:1.持續學習新技術,如雲計算和容器技術;2.積累項目經驗並建立Portfolio;3.建立職業網絡,拓展人脈。

Linux的主要用途包括:1.服務器操作系統,2.嵌入式系統,3.桌面操作系統,4.開發和測試環境。 Linux在這些領域表現出色,提供了穩定性、安全性和高效的開發工具。

互聯網運行不依賴單一操作系統,但Linux在其中扮演重要角色。 Linux廣泛應用於服務器和網絡設備,因其穩定性、安全性和可擴展性受歡迎。

Linux操作系統的核心是其命令行界面,通過命令行可以執行各種操作。 1.文件和目錄操作使用ls、cd、mkdir、rm等命令管理文件和目錄。 2.用戶和權限管理通過useradd、passwd、chmod等命令確保系統安全和資源分配。 3.進程管理使用ps、kill等命令監控和控制系統進程。 4.網絡操作包括ping、ifconfig、ssh等命令配置和管理網絡連接。 5.系統監控和維護通過top、df、du等命令了解系統運行狀態和資源使用情況。

介紹 Linux是一個強大的操作系統,由於其靈活性和效率,開發人員,系統管理員和電源用戶都喜歡。但是,經常使用長而復雜的命令可能是乏味的

Linux適用於服務器、開發環境和嵌入式系統。 1.作為服務器操作系統,Linux穩定高效,常用於部署高並發應用。 2.作為開發環境,Linux提供高效的命令行工具和包管理系統,提升開發效率。 3.在嵌入式系統中,Linux輕量且可定制,適合資源有限的環境。

簡介:通過基於Linux的道德黑客攻擊數字邊界 在我們越來越相互聯繫的世界中,網絡安全至關重要。 道德黑客入侵和滲透測試對於主動識別和減輕脆弱性至關重要


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

WebStorm Mac版
好用的JavaScript開發工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Atom編輯器mac版下載
最受歡迎的的開源編輯器