Linux系統編程---守護進程

1 守護進程的概述

Daemon(守護進程)是運行在后臺的一種特殊進程。它獨立于控制終端并且周期性地執行某種任務或等待處理某些發生的事件。它不需要用戶輸入就能運行而且提供某種服務,不是對整個系統就是對某個用戶程序提供服務。Linux系統的大多數服務器就是通過守護進程實現的。常見的守護進程包括系統日志進程syslogd、 web服務器httpd、郵件服務器sendmail和數據庫服務器mysqld等。

守護進程一般在系統啟動時開始運行,除非強行終止,否則直到系統關機都保持運行。守護進程經常以超級用戶(root)權限運行,因為它們要使用特殊的端口(1-1024)或訪問某些特殊的資源。

守護進程的父進程是init進程,因為它真正的父進程在fork出子進程后就先于子進程exit退出了,所以它是一個由init繼承的孤兒進程。守護進程是非交互式程序,沒有控制終端,所以任何輸出,無論是向標準輸出設備stdout還是標準出錯設備stderr的輸出都需要特殊處理。

守護進程的名稱通常以d結尾,比如sshd、xinetd、crond等。

2 守護進程的創建

首先我們要了解一些基本概念:

進程組 :

  • 每個進程都屬于各自的進程組
  • 每個進程都有一個進程組號,該號等于該進程組組長的PID號 .
  • 一個進程只能為它自己或子進程設置進程組ID號

會話:
會話(session)是一個或多個進程組的集合。setsid()函數可以建立一個新會話:
如果,調用setsid的進程不是一個進程組的組長,此函數創建一個新的會話。

  • 此進程變成該會話的首進程
  • 此進程變成一個新進程組的組長進程。
  • 此進程沒有控制終端,如果在調用setsid前,該進程有控制終端,那么與該終端的聯系被解除。 如果該進程是一個進程組的組長,此函數返回錯誤。
  • 為了保證這一點,我們先調用fork()然后exit(),此時只有子進程在運行,子進程不會是進程組的組長

編寫守護進程的一般步驟步驟:

  1. 在父進程中執行fork并exit推出:保證調用setsid()函數的進程不是進程組組長

  2. 在子進程中調用setsid函數創建新的會話:調用進程成為新的會話組長和新的進程組長,并與原來的會話和進程組脫離。由于會話對控制終端的獨占性,進程同時與控制終端脫離。

  3. 再次 fork() 一個子進程并讓父進程退出:現在,進程已經成為無終端的會話組長,但它可以重新申請打開一個控制終端,可以通過 fork() 一個子進程,該子進程不是會話首進程,該進程將不能重新打開控制終端。退出父進程。

  4. 在子進程中調用chdir函數,讓根目錄 ”/” 成為子進程的工作目錄:使用fork創建的子進程繼承了父進程的當前工作目錄。由于在進程運行中,當前目錄所在的文件系統(如“/mnt/usb”)是不能卸載的,這對以后的使用會造成諸多的麻煩(比如系統由于某種原因要進入單用戶模式)。因此,通常的做法是讓"/"作為守護進程的當前工作目錄,這樣就可以避免上述的問題,當然,如有特殊需要,也可以把當前工作目錄換成其他的路徑,如/tmp。改變工作目錄的常見函數是chdir。

  5. 在子進程中調用umask函數,設置進程的umask為0:進程從創建它的父進程那里繼承了文件創建掩模。它可能修改守護進程所創建的文件的存取位。為防止這一點,將文件創建掩模清除:umask(0)

  6. 在子進程中關閉任何不需要的文件描述符

4、5、6步驟是修改繼承來自父類的資源,順序無所謂。

一張簡單的圖可以完美詮釋之前幾個步驟:
請添加圖片描述
以下程序是創建一個守護進程,然后利用這個守護進程每隔一分鐘向daemon.log文件中寫入當前時間,當守護進程收到 SIGQUIT 信號后退出。

#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>static bool flag = true;
void create_daemon();
void handler(int);int main()
{time_t t;int fd;create_daemon();struct sigaction act;act.sa_handler = handler;sigemptyset(&act.sa_mask);act.sa_flags = 0;if(sigaction(SIGQUIT, &act, NULL)){printf("sigaction error.\n");exit(0);}while(flag){fd = open("/home/mick/daemon.log", O_WRONLY | O_CREAT | O_APPEND, 0644);if(fd == -1){printf("open error\n");}t = time(0);char *buf = asctime(localtime(&t));write(fd, buf, strlen(buf));close(fd);sleep(60);}return 0;
}
void handler(int sig)
{printf("I got a signal %d\nI'm quitting.\n", sig);flag = false;
}
void create_daemon()
{pid_t pid;pid = fork();if(pid == -1){printf("fork error\n");exit(1);}else if(pid){exit(0);}if(-1 == setsid()){printf("setsid error\n");exit(1);}pid = fork();if(pid == -1){printf("fork error\n");exit(1);}else if(pid){exit(0);}chdir("/");int i;for(i = 0; i < 3; ++i){close(i);}umask(0);return;
}

注意守護進程一般需要在 root 權限下運行。

通過

ps -ef | grep 'daemon'

可以看到:

root     26454  2025  0 14:20 ?        00:00:00 ./daemon

并且產生了 daemon.log,里面是這樣的時間標簽

Thu Dec  8 14:35:11 2016
Thu Dec  8 14:36:11 2016
Thu Dec  8 14:37:11 2016

最后我們想退出守護進程,只需給守護進程發送 SIGQUIT 信號即可

sudo kill -3 26454 

再次使用 ps 會發現進程已經退出。

3 利用庫函數daemon()創建守護進程

其實我們完全可以利用 daemon() 函數創建守護進程,其函數原型:

#include <unistd.h>int daemon(int nochdir, int noclose);DESCRIPTION         The daemon() function is for programs wishing to detach themselvesfrom the controlling terminal and run in the background as systemdaemons.If nochdir is zero, daemon() changes the process's current workingdirectory to the root directory ("/"); otherwise, the current workingdirectory is left unchanged.If noclose is zero, daemon() redirects standard input, standardoutput and standard error to /dev/null; otherwise, no changes aremade to these file descriptors.RETURN VALUE         (This function forks, and if the fork(2) succeeds, the parent calls_exit(2), so that further errors are seen by the child only.)  Onsuccess daemon() returns zero.  If an error occurs, daemon() returns-1 and sets errno to any of the errors specified for the fork(2) andsetsid(2).

daemon() 函數將調用進程變成守護進程。
參數:

nochdir:=0將當前目錄更改至“/”

noclose:=0將標準輸入、標準輸出、標準錯誤重定向至“/dev/null”

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>#define ERR_EXIT(m) \
do\
{\perror(m);\exit(EXIT_FAILURE);\
}\
while (0);\

void creat_daemon(void);
int main(void)
{time_t t;int fd;if(daemon(0,0) == -1)ERR_EXIT("daemon error");while(1){fd = open("daemon.log",O_WRONLY|O_CREAT|O_APPEND,0644);if(fd == -1)ERR_EXIT("open error");t = time(0);char *buf = asctime(localtime(&t));write(fd,buf,strlen(buf));close(fd);sleep(60);        }return 0;
}

運行結果和上面一樣

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379499.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379499.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379499.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c ++明明的隨機數_從列表C ++程序中隨機建議電影

c 明明的隨機數Problem statement: 問題陳述&#xff1a; Write an application code that will suggest movies from a list randomly and there wont be any repeat while suggesting the movies. That means the same movie wont be suggested twice though it will be don…

郵箱服務器

一&#xff0e;郵箱服務器的基本概念 郵件的客戶端&#xff1a;可以只安裝在電腦上&#xff08;C/S&#xff09;的也可以是網頁形式&#xff08;B/S&#xff09;的 郵件服務器&#xff1a;起到郵件的接受與推送的作用 郵件發送的協議&#xff1a; 協議&#xff1a;就是數據傳輸…

C#提高保存jpg圖像的質量

在程序中直接生成的jpg圖像&#xff0c;漢字有毛邊&#xff0c;經過一番搜索&#xff0c;在msdn上發現了下面控制jpg質量系數的文章&#xff0c;修改后試了一下&#xff0c;效果確實比前面強多了。原理我也不大懂&#xff0c;把代碼貼出來&#xff0c;與大家共享。 聯合圖…

延遲和定時器管理

文章目錄1 內核中時間概念2 標準定時器jiffies和HZ定時器API標準定時器案例3 高精度定時器(HRT)高精度定時器案例4 內核中延遲和睡眠原子上下文非原子上下文1 內核中時間概念 時間概念對計算機來說有些模糊&#xff0c;事實上內核必須在硬件的幫助下才能計算和管理時間。硬件為…

Web開發工具(插件)收集

1.IE Developer Toolbar 瀏覽和修改&#xff0c;選定Web頁上的特定元素&#xff0c;查看HTML對象的類名、ID&#xff0c;以及類似鏈接路徑、tab順序、快捷鍵等。 2.HttpWatch Professional 一款強大的網頁數據分析工具,可以查看當前網頁的http數據 FireFox插件 FireFox下插件實…

cin、cin.get()、cin.getline()、getline()、gets()等函數的用法

轉載&#xff0c;并經過本人補充cin、cin.get()、cin.getline()、getline()、gets()等函數的用法2007/10/27 22:51學C的時候&#xff0c;這幾個輸入函數弄的有點迷糊&#xff1b;這里做個小結&#xff0c;為了自己復習&#xff0c;也希望對后來者能有所幫助&#xff0c;如果有差…

Java StringBuilder subSequence()方法與示例

StringBuilder類subSequence()方法 (StringBuilder Class subSequence() method) subSequence() method is available in java.lang package. subSequence()方法在java.lang包中可用。 subSequence() method is used to return the new set of a character sequence that is a …

Linux設備驅動開發---設備樹的概念

文章目錄1 設備樹機制命名約定別名、標簽和phandleDT編譯器2 表示和尋址設備SPI和I2C尋址平臺設備尋址3 處理資源提取特定應用數據文本字符串單元格和無符號的32位整數布爾提取并分析子節點4 平臺驅動程序與DTOF匹配風格處理非設備樹平臺平臺數據與DT設備樹&#xff08;DT&…

【轉】C#中數組復制的4種方法

C#中數組復制的4種方法 from&#xff1a;http://blog.csdn.net/burningcpu/article/details/1434167今天旁邊的同事MM叫我調了一段程序&#xff0c;她想復制一個數組&#xff0c;int[] pins {9,3,4,9};int [] alias pins;這里出了錯誤&#xff0c;也是錯誤的根源&#xff0c…

Java StringBuilder codePointAt()方法與示例

StringBuilder類codePointAt()方法 (StringBuilder Class codePointAt() method) codePointAt() method is available in java.lang package. codePointAt()方法在java.lang包中可用。 codePointAt() method is used to return the Unicode code point at the given indices an…

用戶虛擬地址轉化成物理地址,物理地址轉換成內核虛擬地址,內核虛擬地址轉換成物理地址,虛擬地址和對應頁的關系

文章目錄1. 用戶虛擬地址轉換成物理地址2. 內核虛擬地址轉換成物理地址3. 物理地址轉換成內核虛擬地址4 內核虛擬地址和對應頁5 根據進程號獲取進程描述符1. 用戶虛擬地址轉換成物理地址 static void get_pgtable_macro(void) {printk("PAGE_OFFSET 0x%lx\n", PAGE…

簡單三層架構(登錄)

1&#xff0c;首先導包 dao //獲取數據String username request.getParameter("username");String password request.getParameter("password");//傳遞到Service層UserService service new UserService();//這里的UserService 需要創建到service包下Use…

通過隱藏option實現select的聯動效果

開始的時候需求是根據一定條件隱藏一部分<option>標簽&#xff0c;類似聯動效果&#xff0c;但是目前的html規范并沒有為<option>提供隱藏的效果&#xff0c;因此常用的設置display或者visibility無效。網上大部分解決方案是刪除<option>節點或<option>…

Java SimpleTimeZone setEndRule()方法與示例

SimpleTimeZone類setEndRule()方法 (SimpleTimeZone Class setEndRule() method) Syntax: 句法&#xff1a; public void setEndRule(int en_mm, int en_dd, int en_time);public void setEndRule(int en_mm, int en_dd, int en_dow, int en_time);public void setEndRule(int…

Linux設備驅動開發--- DMA

文章目錄1 設置DMA映射緩存一致性和DMADMA映射一致映射流式DMA映射2 完成的概念3 DMA引擎API分配DMA從通道設置從設備和控制器指定參數獲取事務描述符提交事務發布待處理DMA請求并等待回調通知4 程序單緩沖區映射分散聚集映射DMA是計算機系統的一項功能&#xff0c;它允許設備在…

類加載器

一、類加載器 1&#xff0c;什么是類加載器&#xff1f; 類加載器就是用來加載字節碼文件 2&#xff0c;類加載器的種類有哪些&#xff1f; 1&#xff09;BootStrap&#xff1a;引導類加載器&#xff1a;加載都是最基礎的文件 2&#xff09;ExtClassLoader&#xff1a;擴展類加…

一個用java讀取XML文件的簡單方法(轉)

XML文件 book.xml <book> <person> <first>Kiran</first> <last>Pai</last> <age>22</age> </person> <person> <first>Bill</first> <last>Gates</last> <age>46</age&g…

Java ObjectStreamField getName()方法與示例

ObjectStreamField類的getName()方法 (ObjectStreamField Class getName() method) getName() method is available in java.io package. getName()方法在java.io包中可用。 getName() method is used to get the name of this ObjectStreamField field. getName()方法用于獲取…

【css】CSS中折疊margin的問題

為什么要翻譯這篇說明&#xff1f;css2本有人已翻譯過&#xff0c;但看一下&#xff0c;很粗糙&#xff08;不是說自己就怎么怎么樣啊&#xff0c;翻譯者真的是很值得敬佩的&#xff01;&#xff09;&#xff0c;近來跟css與xhtml接觸得越來越多&#xff0c;但接觸得越多&#…

算法---鏈表

文章目錄反轉鏈表合并兩個有序鏈表刪除重復元素反轉鏈表 反轉鏈表包括兩種&#xff0c;反轉全部元素或者反轉部分元素。在這里&#xff0c;我們約定&#xff1a;數據元素類型是struct LinkNode&#xff0c;要反轉鏈表的第一個節點是head&#xff0c;head的前面一個節點是pre&a…