<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      創建 SysV 風格的 linux daemon 程序

      本文介紹如何使用 C 語言創建 Linux 系統中 SysV 風格的 daemon 程序。注意:這是一種舊式的 daemon 程序寫法,進入 systemd 時代后是不需要通過這樣的方式創建 daemon 程序的。 本文的演示環境為 ubuntu 18.04。

      創建 daemon 程序的流程

      通過前文《Linux session(會話)》我們了解到,如果要讓程序運行在后臺,必須處理好進程的 session。所以在創建 daemon 程序的過程中處理 session 問題是很重要的一步,當然除此之外還需要其它的步驟。下面是在 Linux 系統中創建一個 SysV 風格的 daemon 的基本流程:

      1. 從父進程 fork 出一個子進程
      2. 為子進程創建新的 session ID
      3. 在子進程中再 fork 一次
      4. 修改 umask
      5. 修改進程的當前工作目錄
      6. 關閉進程中的文件描述符

      接下來我們通過代碼來介紹這些操作的含義。

      創建 daemon 程序

      從父進程 fork 出一個子進程
      創建一個子進程,如果成功就讓父進程退出,此時的子進程已經成為了 init 進程的子進程:

      pid_t pid;
      
      pid = fork();
      if (pid < 0)
          exit(EXIT_FAILURE);
      if (pid > 0)
          exit(EXIT_SUCCESS);

      為子進程創建新的 session ID
      運行在后臺的進程需要擺脫 session 終端的束縛,通過 setsid() 函數為進程設置新的 session ID 可以做到這一點:

      pid_t pid;
      
      pid = fork();
      if (pid < 0)
          exit(EXIT_FAILURE);
      if (pid > 0)
          exit(EXIT_SUCCESS);
      
      if (setsid() < 0)
          exit(EXIT_FAILURE);

      ********************************
      執行到這里時,PID==PGID==SID

      ********************************

      在子進程中再 fork 一次
      這次 fork 的目的是防止進程再次獲得終端。因為只有 session leader 才能獲得終端,而這次 fork 使子進程變成了非 session leader:

      pid_t pid;
      
      pid = fork();
      if (pid < 0)
          exit(EXIT_FAILURE);
      if (pid > 0)
          exit(EXIT_SUCCESS);
      
      if (setsid() < 0)
          exit(EXIT_FAILURE);
          
      /* 第二次 fork */
      pid = fork();
      if (pid < 0)
          exit(EXIT_FAILURE);
      
      if (pid > 0)
          exit(EXIT_SUCCESS);

      ********************************
      執行到這里時,PGID==SID 但是已經不等于 PID 了,說明進程已經不是 session leader

      ********************************

      修改 umask
      為了能夠向 daemon 進程創建的任何文件中寫入內容(包括日志),必須重置 umask(file mode mask, umask),以確保能夠正確地寫入或讀取這些文件:

      umask(0);

      修改進程的當前工作目錄
      必須保證進程的當前工作目錄是存在的。因為眾多的 Linux 發行版中很多都沒有完全遵守標準的文件目錄結構,所以最好是把進程的當前工作目錄設置為 /,這樣可以避免因設置了某個目錄而導致它無法被 unmount:

      chdir("/");

      關閉進程中的文件描述符
      關閉進程中所有打開的文件描述符:

      int x;
      for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
      {
          close (x);
      }


      把日志寫入 syslog
      Daemon 程序的日志非常重要,我們可以通過 openlog、syslog 和 closelog 三個函數把日志內容寫入到 syslog  中:

      openlog ("daemondemo", LOG_PID, LOG_DAEMON);
      syslog (LOG_NOTICE, "Daemon demo is running, number: %d", count);
      closelog();

      本文 demo 輸出的日志如下所示:

      完整的代碼

      #include <stdio.h>
      #include <stdlib.h>
      #include <unistd.h>
      #include <signal.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <syslog.h>
      
      static void demo_daemon()
      {
          pid_t pid;
      
          /* Fork off the parent process */
          pid = fork();
      
          /* An error occurred */
          if (pid < 0)
              exit(EXIT_FAILURE);
      
          /* Success: Let the parent terminate */
          if (pid > 0)
              exit(EXIT_SUCCESS);
      
          /* On success: The child process becomes session leader */
          if (setsid() < 0)
              exit(EXIT_FAILURE);
      
          /* Catch, ignore and handle signals */
          //TODO: Implement a working signal handler */
          //signal(SIGCHLD, SIG_IGN);
          //signal(SIGHUP, SIG_IGN);
      
          /* Fork off for the second time*/
          pid = fork();
      
          /* An error occurred */
          if (pid < 0)
              exit(EXIT_FAILURE);
      
          /* Success: Let the parent terminate */
          if (pid > 0)
              exit(EXIT_SUCCESS);
      
          /* Set new file permissions */
          umask(0);
      
          /* Change the working directory to the root directory */
          /* or another appropriated directory */
          chdir("/");
      
          /* Close all open file descriptors */
          int x;
          for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
          {
              close (x);
          }
      
          /* Open the log file */
          openlog ("daemondemo", LOG_PID, LOG_DAEMON);
      }
      
      int main()
      {
          int count = 0;
          demo_daemon();
      
          while (1)
          {
              //TODO: Insert daemon code here.
              count ++;
              syslog (LOG_NOTICE, "Daemon demo is running, number: %d", count);
              sleep (5);
              if(count > 5)
              {
                  break;
              }
          }
      
          syslog (LOG_NOTICE, "Daemon demo terminated.");
          closelog();
      
          return EXIT_SUCCESS;
      }

      把上面的代碼保存到文件 daemondemo.c 中(也可以從這里下代碼),然后執行下面的命令進行編譯就可以得到可執行文件 daemondemo:

      $ gcc -Wall daemondemo.c -o daemondemo

      關于 fork 兩次

      這是一個很有意思的話題,有人說需要 fork 兩次,有人說第二次是可選的,究竟該如何做呢?當我們理解了第二次 fork 的用途后就可以自行決定是否需要第二次 fork 了。
      這還需要從 session 的控制終端說起。控制終端是進程的一個屬性,通過 fork 系統調用創建的子進程會從父進程那里繼承控制終端。這樣,session 中的所有進程都從 session 領頭進程那里繼承控制終端。前面已經說過了,要把程序變成 daemon,就得讓進程擺脫 session 的終端。而這些在第一次 fork 后調用 setsid() 函數就搞定了。那么如果接下來不小心再給進程添加了終端該怎么辦?答案是不讓你添加!這就是第二次 fork 的作用。只有 session leader 才能獲得終端,而第二次 fork 使子進程變成了非 session leader,你想犯錯也不給你機會了。

      像 nginx 和 gblic 的 daemon 函數的實現都是 fork 一次,所以說第二次 fork 是可選的,你可以根據自己的實際情況來決定。

      參考:
      Linux Daemon Writing HOWTO
      Creating a daemon in Linux
      daemon man page
      daemon 函數
      Unix Daemon Server Programming
      glibc daemon.c

      posted @ 2020-04-17 08:32  sparkdev  閱讀(1960)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 久热这里只有精品12| 99国精品午夜福利视频不卡99| 国内精品伊人久久久久AV一坑 | 亚洲免费一区二区av| 日韩有码精品中文字幕| 无码熟妇人妻av在线电影| 国产情侣激情在线对白| 深夜福利成人免费在线观看 | 亚洲中文字幕无码爆乳APP| 蜜桃无码一区二区三区| 国产欧美精品一区二区三区-老狼| 国产亚洲AV电影院之毛片| 成熟了的熟妇毛茸茸| 亚洲乱码精品久久久久..| 一区二区亚洲人妻av| 自拍日韩亚洲一区在线| 亚洲人成小说网站色在线| 亚洲韩国精品无码一区二区三区| 国产美女高潮流白浆视频| 中文字幕精品无码一区二区三区| 中文字幕精品无码一区二区| 一区二区三区四区黄色片| 亚洲情综合五月天| 国产高清自产拍av在线| 亚洲成av人最新无码不卡短片| 亚洲视频免费一区二区三区| 无套内射视频囯产| 中文字幕乱偷无码av先锋蜜桃| 麻豆果冻国产剧情av在线播放| 欧美和黑人xxxx猛交视频| 成人看的污污超级黄网站免费| 一区一区三区产品乱码| 国产资源精品中文字幕| 无码人妻久久一区二区三区app| 亚洲AV无码专区亚洲AV紧身裤| 五月丁香啪啪| 久爱无码精品免费视频在线观看| 精品久久久久久无码免费| 亚洲人成电影网站色mp4| 精品人妻系列无码天堂| 一区二区三区午夜无码视频|