创建守护进程
守護進程(daemon)。 守護進程是一個后臺進程,它無需用戶輸入就能運行,經常是提供某種服務。 Linux做為服務器是,主要的進程也都是為系統或者用戶提供后臺服務功能。 常見的守護進程有Web服務器、郵件服務器以及數據庫服務器等等。 守護進程不能夠控制終端,所以任何輸入或者輸出都需要做特殊處理。 守護進程看上去似乎很神秘,但如果牢記幾條規則而且知道幾個關鍵函數,工作就很簡單了。 首先執行fork后讓父進程退出。 和多數程序一樣,一個守護進程是從shell腳本或者命令行啟動的。 但守護進程和應用程序不一樣,因為它們不是交互式的 –它們在后臺因而沒有控制終端。 父進程在fork子進程退出后就消除了控制終端。 守護進程既不需要從標準輸入設備讀信息,也不需要從標準輸出設備輸出信息。 下一步是在子進程中使用setsid調用創建新會話,調用setsid完成以下幾項工作。 –如果調用進程不是一個進程組的領導進程,它就創建一個新會話,讓調用進程成為新會話的會話領導。 –它讓調用進程成為新進程組的進程組領導。 –它把進程組ID(PGID)和會話ID(SID)設置為調用進程的進程ID(PID)。 –它取消進程和任何控制終端的關聯。 下一步是讓根目錄成為子進程的當前工作目錄。 因為任何進程如果它的當前目錄是在一個被安裝的文件系統上,那么就會妨礙這個文件系統被卸載。 接下來設置進程的umask為0。 為了避免守護進程集成的umask收到創建文件和目錄操作的干擾,這一步是必要的。 如果一個進程集成了父進程的umask 055,他屏蔽掉了group和other的讀和執行權。如果守護進程接著創建了一個文件,那么對group和other用戶操作這個文件會帶來麻煩。 守護進程調用 umask 0避免了這種情況,當創建文件的時候給予守護進程更大的靈活性。 最后關閉子進程繼承的任何不必要的文件描述符。 對于子進程來說,沒有理由保持從父進程繼承來的打開的文件描述符。 具體關閉哪些取決與具體的守護進程需要和要求,很難精確的說明規則。 創建守護進程步驟總結 –父進程中執行fork后,執行exit退出。 –在子進程中調用setsid。 –讓根目錄“/”成為子進程的工作目錄。 –把子進程的umask變為0。 –關閉任何不需要的文件描述符。 setsid函數 pid_t setsid() setsid函數創建一個新會話和一個新進程組,然后守護進程成為新會話的會話領導,以及新進程組的進程組領導。 setsid調用還保證新會話沒有控制終端。 如果調用進程已經是一個進程組的領導進程,setsid調用失敗。 setsid調用成功返回新會話ID,失敗返回-1,并設置errno。 chdir函數 int chdir(const char *pathname) chdir函數根據參數pathname設置當前工作。 chdir調用成功返回0,失敗返回-1,并設置errno。 umask函數 mode_t umask(mode_t mask); umask調用把守護進程的umask設置為0,這樣取消了來自父進程的umask,它們能夠潛在的干擾創建文件和目錄。 創建守護進程代碼例子。 void setdaemon()
{pid_t pid, sid;pid = fork();if (pid < 0){printf("fork failed\n");exit(EXIT_FAILURE);}if(pid > 0){exit(EXIT_SUCCESS);//in the parent
}if((sid = setsid()) < 0){printf("setsid failed\n");exit(EXIT_FAILURE);}if((chdir("/")) < 0){printf("chdir failed\n");exit(EXIT_FAILURE);}umask(0);//close(STDIN_FILENO);//if close stdin,then daemon_console failed
close(STDOUT_FILENO);close(STDERR_FILENO);
}
?
?
一旦系統調用setsid,它就不再有控制終端,所以也就無處發送正常情況下應該發往stdout或者stderr的輸出。 可以通過syslog提供服務,記錄守護進程的各種輸出信息。 openlog函數打開日志,syslog寫入日志,closelog關閉日志。 #include <syslog.h> void openlog(const char *ident, int option, int facility); void syslog(int priority, const char *format, ...); void closelog(void); openlog函數發起到系統日志服務器的連接,參數ident是要向每個消息加入的字符串,典型的情況是要設置成程序的名稱。 參數option是下面一個或多個值的“或”| 名稱 | 含義 |
| LOG_CONS | 如果系統日志服務器不能用,寫入控制臺 |
| LOG_NDELAY | 立即打開連接,正常情況下,直到發送第一條消息才打開連接 |
| LOG_PERROR | 打印輸出到stderr |
| LOG_PID | 每條消息中包含進程 PID |
?
?
參數facitity指定程序發送消息的類型。| 名稱 | 含義 |
| LOG_AUTHPRIV | 安全授權消息 |
| LOG_CRON | 時鐘守護進程:cron和at |
| LOG_DAEMON | 其他系統守護進程 |
| LOG_KERN | 內核消息 |
| LOG_LPR | 打印機子系統 |
| LOG_MAIL | 郵件子系統 |
| LOG_USER | 默認 |
?
?
參數priority指定消息的重要性。| 名稱 | 含義 |
| LOG_EMERG | 系統不能使用 |
| LOG_ALERT | 立即采取措施 |
| LOG_CRIT | 緊急事件 |
| LOG_ERR | 出錯條件 |
| LOG_WARNING | 警告條件 |
| LOG_NOTICE | 正常但重大事件 |
| LOG_INFO | 信息消息 |
| LOG_DEBUG | 調試信息 |
?
?
syslog代碼例子:yslog(LOG_INFO, "my daemin is OK");
嚴格的說,openlog和closelog是可選的,因為函數syslog在首次使用的時候自動打開日志文件。 linux系統上日志文件通常是/var/log/messages。 復制去Google翻譯翻譯結果轉載于:https://www.cnblogs.com/shichuan/p/4496188.html
總結