Tạo daemon trong Linux


110

Trong Linux, tôi muốn thêm một daemon không thể dừng lại và nó giám sát các thay đổi của hệ thống tệp. Nếu bất kỳ thay đổi nào được phát hiện, nó sẽ ghi đường dẫn đến bảng điều khiển nơi nó được bắt đầu cùng với một dòng mới.

Tôi đã có mã thay đổi hệ thống tệp gần như sẵn sàng nhưng tôi không thể tìm ra cách tạo một daemon.

Mã của tôi từ đây: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

Làm gì sau ngã ba?

int main (int argc, char **argv) {

  pid_t pID = fork();
  if (pID == 0)  {              // child
          // Code only executed by child process    
      sIdentifier = "Child Process: ";
    }
    else if (pID < 0) {
        cerr << "Failed to fork" << endl;
        exit(1);
       // Throw exception
    }
    else                                   // parent
    {
      // Code only executed by parent process

      sIdentifier = "Parent Process:";
    }       

    return 0;
}

1
Có thể trùng lặp: stackoverflow.com/q/5384168/1076451
Chimera

1
bản sao có thể có của: stackoverflow.com/questions/5384168/… đối với phần daemonize, stackoverflow.com/questions/931093/… đối với đồng hồ hệ thống tệp
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Nếu bạn không cần tuân thủ POSIX, bạn có thể quan tâm đến inotifyAPI. Xem: inotify_init, inotify_add_watch, inotify_rm_watch.
patryk.beza

Câu trả lời:


216

Trong Linux, tôi muốn thêm một daemon không thể dừng lại và nó giám sát các thay đổi của hệ thống tệp. Nếu bất kỳ thay đổi nào được phát hiện, nó sẽ ghi đường dẫn đến bảng điều khiển nơi nó được bắt đầu + một dòng mới.

Daemon hoạt động trong nền và (thường là ...) không thuộc về TTY, đó là lý do tại sao bạn không thể sử dụng stdout / stderr theo cách bạn có thể muốn. Thông thường, một daemon nhật ký hệ thống ( syslogd ) được sử dụng để ghi thông báo vào tệp (gỡ lỗi, lỗi, ...).

Bên cạnh đó, có một số bước bắt buộc để tạo ra một quy trình.


Nếu tôi nhớ không nhầm thì các bước này là:

  • fork khỏi quy trình gốc và để nó kết thúc nếu quá trình fork thành công. -> Bởi vì tiến trình mẹ đã kết thúc, tiến trình con bây giờ chạy ở chế độ nền.
  • setid - Tạo một phiên mới. Quá trình gọi trở thành người lãnh đạo của phiên mới và người lãnh đạo nhóm quá trình của nhóm quá trình mới. Quy trình hiện được tách ra khỏi thiết bị đầu cuối điều khiển (CTTY).
  • Bắt tín hiệu - Bỏ qua và / hoặc xử lý tín hiệu.
  • fork lần nữa & để quá trình gốc kết thúc để đảm bảo rằng bạn thoát khỏi quá trình dẫn đầu phiên. (Chỉ những người lãnh đạo phiên mới có thể nhận lại TTY.)
  • chdir - Thay đổi thư mục làm việc của daemon.
  • umask - Thay đổi mặt nạ chế độ tệp theo nhu cầu của daemon.
  • close - Đóng tất cả các bộ mô tả tệp đang mở có thể được kế thừa từ quy trình mẹ.

Để cung cấp cho bạn điểm bắt đầu: Hãy xem mã khung này hiển thị các bước cơ bản. Mã này bây giờ cũng có thể được fork trên GitHub: Bộ xương cơ bản của daemon linux

/*
 * daemonize.c
 * This example daemonizes a process, writes a few log messages,
 * sleeps 20 seconds and terminates afterwards.
 */

#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 skeleton_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 ("firstdaemon", LOG_PID, LOG_DAEMON);
}
int main()
{
    skeleton_daemon();

    while (1)
    {
        //TODO: Insert daemon code here.
        syslog (LOG_NOTICE, "First daemon started.");
        sleep (20);
        break;
    }

    syslog (LOG_NOTICE, "First daemon terminated.");
    closelog();

    return EXIT_SUCCESS;
}


  • Biên dịch mã: gcc -o firstdaemon daemonize.c
  • Khởi động daemon: ./firstdaemon
  • Kiểm tra xem mọi thứ có hoạt động bình thường không: ps -xj | grep firstdaemon

  • Đầu ra phải tương tự như sau:

+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
| PPID | PID | PGID | SID | TTY | TPGID | THỐNG KÊ | UID | THỜI GIAN | CMD |
+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
| 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ |
+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +

Những gì bạn sẽ thấy ở đây là:

  • Daemon không có thiết bị đầu cuối điều khiển ( TTY =? )
  • ID quy trình mẹ ( PPID ) là 1 (Quy trình init)
  • Các PID! = SID có nghĩa là quá trình của chúng tôi là không lãnh đạo phiên
    (vì ngã ba thứ hai ())
  • Vì PID! = SID nên quy trình của chúng tôi không thể kiểm soát lại TTY

Đọc nhật ký hệ thống:

  • Định vị tệp nhật ký hệ thống của bạn. Của tôi ở đây:/var/log/syslog
  • Làm một: grep firstdaemon /var/log/syslog

  • Đầu ra phải tương tự như sau:

  firstdaemon [3387]: Daemon đầu tiên bắt đầu.
  firstdaemon [3387]: Daemon đầu tiên chấm dứt.


Lưu ý: Trong thực tế, bạn cũng sẽ muốn triển khai một trình xử lý tín hiệu và thiết lập ghi nhật ký đúng cách (Tệp, cấp độ nhật ký ...).

Đọc thêm:


Ồ cảm ơn nhé! Thật tuyệt. Vì vậy, tôi phải đặt mã của mình vào Vòng lặp trong khi và đó là nó?
chrisMe,

Về cơ bản, có. Nhưng mã này chỉ là một ví dụ. Nó hoàn toàn phụ thuộc vào những gì bạn muốn đạt được bằng cách sử dụng quy trình daemon. Hãy chắc chắn để đọc câu trả lời này quá: @Edwin
Pascal Werkl

1
Thay vì thứ hai fork(), tại sao không chỉ sử dụng setsid()?
Chimera

1
Lưu ý rằng các sigaction()chức năng cung cấp một cơ chế toàn diện hơn và đáng tin cậy cho việc kiểm soát tín hiệu; các ứng dụng mới nên sử dụng sigaction()hơn là signal().
patryk.beza

4
Cần lưu ý với người xem rằng phương pháp này là cách "cũ". Cách mới được đề xuất để tạo daemon là với "daemon kiểu mới" được tìm thấy tại đây: 0pointer.de/public/systemd-man/daemon.html#New-Style%20Daemons hoặc
Starlord 20/02/18

30

man 7 daemonmô tả cách tạo daemon rất chi tiết. Câu trả lời của tôi chỉ là phần trích dẫn từ sách hướng dẫn này.

Có ít nhất hai loại daemon:

  1. daemon SysV truyền thống (kiểu ),
  2. hệ thống daemon (kiểu mới ).

SysV Daemons

Nếu bạn quan tâm đến daemon SysV truyền thống , bạn nên thực hiện các bước sau :

  1. Đóng tất cả các bộ mô tả tệp đang mở ngoại trừ đầu vào , đầu ralỗi chuẩn (tức là ba bộ mô tả tệp đầu tiên 0, 1, 2). Điều này đảm bảo rằng không có bộ mô tả tệp vô tình được chuyển vào trong quy trình daemon. Trên Linux, điều này được thực hiện tốt nhất bằng cách lặp đi lặp lại /proc/self/fd, với dự phòng là lặp lại từ bộ mô tả tệp 3 đến giá trị được trả về bởi getrlimit()for RLIMIT_NOFILE.
  2. Đặt lại tất cả các bộ xử lý tín hiệu về mặc định của chúng. Điều này được thực hiện tốt nhất bằng cách lặp lại các tín hiệu có sẵn cho đến giới hạn _NSIGvà đặt lại chúng SIG_DFL.
  3. Đặt lại mặt nạ tín hiệu bằng cách sử dụng sigprocmask().
  4. Vệ sinh khối môi trường, xóa hoặc đặt lại các biến môi trường có thể ảnh hưởng tiêu cực đến thời gian chạy của daemon.
  5. Gọi fork(), để tạo một quy trình nền.
  6. Trong phần con, gọi setsid()để tách khỏi bất kỳ thiết bị đầu cuối nào và tạo một phiên độc lập .
  7. Trong phần con, hãy gọi fork()lại, để đảm bảo rằng daemon không bao giờ có thể lấy lại một thiết bị đầu cuối nữa.
  8. Gọi exit()con đầu tiên, để chỉ con thứ hai (tiến trình daemon thực tế) ở xung quanh. Điều này đảm bảo rằng quy trình daemon được cấp lại thành init / PID 1, như tất cả các daemon phải như vậy.
  9. Trong quy trình daemon, kết nối /dev/nullvới đầu vào , đầu ralỗi tiêu chuẩn .
  10. Trong quá trình daemon, reset umaskvề 0, do đó các phương thức tập tin truyền cho open(), mkdir()và như vậy trực tiếp kiểm soát chế độ truy cập các tập tin được tạo ra và thư mục.
  11. Trong tiến trình daemon, hãy thay đổi thư mục hiện tại thành thư mục gốc ( /), để tránh daemon vô tình chặn các điểm gắn kết không được gắn kết.
  12. Trong quy trình daemon, ghi PID daemon (như được trả về bởi getpid()) vào một tệp PID, chẳng hạn /run/foobar.pid(đối với một daemon giả định "foobar") để đảm bảo rằng daemon không thể được khởi động nhiều lần. Điều này phải được triển khai theo kiểu không có chủng tộc để tệp PID chỉ được cập nhật khi nó được xác minh đồng thời rằng PID được lưu trữ trước đó trong tệp PID không còn tồn tại hoặc thuộc về một quy trình nước ngoài.
  13. Trong quy trình daemon, hãy bỏ đặc quyền, nếu có thể và có thể áp dụng được.
  14. Từ quy trình daemon, thông báo quy trình ban đầu đã bắt đầu rằng quá trình khởi tạo đã hoàn tất. Điều này có thể được thực hiện thông qua một đường ống không có tên hoặc kênh giao tiếp tương tự được tạo trước lần đầu tiên fork()và do đó có sẵn trong cả quá trình gốc và quá trình daemon.
  15. Gọi exit()trong quy trình ban đầu. Quá trình gọi ra daemon phải có thể dựa vào rằng điều này exit()xảy ra sau khi quá trình khởi tạo hoàn tất và tất cả các kênh giao tiếp bên ngoài được thiết lập và có thể truy cập được.

Lưu ý cảnh báo này:

Không nên sử dụng daemon()hàm BSD vì nó chỉ thực hiện một tập hợp con của các bước này.

Một daemon cần cung cấp khả năng tương thích với các hệ thống SysV nên triển khai sơ đồ đã nêu ở trên. Tuy nhiên, bạn nên đặt hành vi này là tùy chọn và có thể cấu hình thông qua đối số dòng lệnh để dễ gỡ lỗi cũng như đơn giản hóa việc tích hợp vào hệ thống bằng systemd.

Lưu ý rằng daemon()không tuân thủ POSIX .


Daemons kiểu mới

Đối với daemon kiểu mới, các bước sau được khuyến nghị:

  1. Nếu SIGTERMnhận được, hãy tắt daemon và thoát sạch.
  2. Nếu SIGHUPnhận được, hãy tải lại tệp cấu hình, nếu điều này áp dụng.
  3. Cung cấp mã thoát chính xác từ quy trình daemon chính, vì mã này được hệ thống init sử dụng để phát hiện các lỗi và sự cố dịch vụ. Bạn nên làm theo lược đồ mã thoát như được định nghĩa trong các khuyến nghị LSB cho các tập lệnh init SysV .
  4. Nếu có thể và có thể áp dụng, hãy hiển thị giao diện điều khiển của daemon thông qua hệ thống D-Bus IPC và lấy tên xe buýt như bước cuối cùng của quá trình khởi tạo.
  5. Để tích hợp trong systemd, hãy cung cấp tệp đơn vị .service mang thông tin về việc khởi động, dừng và duy trì daemon. Xem chi tiết.systemd.service(5)
  6. Càng nhiều càng tốt, hãy dựa vào chức năng của hệ thống init để giới hạn quyền truy cập của daemon vào các tệp, dịch vụ và các tài nguyên khác, tức là trong trường hợp của systemd, hãy dựa vào kiểm soát giới hạn tài nguyên của systemd thay vì triển khai của riêng bạn, dựa vào việc giảm đặc quyền của systemd mã thay vì triển khai nó trong daemon và tương tự. Xem systemd.exec(5)các điều khiển có sẵn.
  7. Nếu D-Bus được sử dụng, hãy kích hoạt bus daemon của bạn bằng cách cung cấp tệp cấu hình kích hoạt dịch vụ D-Bus . Điều này có nhiều ưu điểm: daemon của bạn có thể được khởi động một cách lười biếng theo yêu cầu; nó có thể được khởi động song song với các daemon khác yêu cầu nó - tối đa hóa tốc độ song song và khởi động ; daemon của bạn có thể được khởi động lại khi bị lỗi mà không làm mất bất kỳ yêu cầu bus nào, vì bus xếp hàng yêu cầu các dịch vụ có thể kích hoạt. Xem chi tiết bên dưới .
  8. Nếu daemon của bạn cung cấp dịch vụ cho các quy trình cục bộ khác hoặc các máy khách từ xa thông qua một ổ cắm, thì nó phải được đặt ở chế độ có thể kích hoạt ổ cắm theo sơ đồ được chỉ ra bên dưới . Giống như kích hoạt D-Bus, điều này cho phép khởi động dịch vụ theo yêu cầu cũng như cho phép cải thiện khả năng khởi động dịch vụ song song. Ngoài ra, đối với các giao thức ít trạng thái (chẳng hạn như nhật ký hệ thống, DNS), một daemon triển khai kích hoạt dựa trên ổ cắm có thể được khởi động lại mà không mất một yêu cầu nào. Xem bên dưới chi tiết .
  9. Nếu có thể, một daemon sẽ thông báo cho hệ thống init về việc hoàn thành khởi động hoặc cập nhật trạng thái thông qua sd_notify(3) giao diện.
  10. Thay vì sử dụng lệnh syslog()gọi để đăng nhập trực tiếp vào dịch vụ nhật ký hệ thống hệ thống, một daemon kiểu mới có thể chọn đăng nhập đơn giản thông qua lỗi chuẩn fprintf(), sau đó được chuyển tiếp đến nhật ký hệ thống bởi hệ thống init. Nếu cấp độ nhật ký là cần thiết, chúng có thể được mã hóa bằng cách thêm tiền tố các dòng nhật ký riêng lẻ bằng các chuỗi như "<4>" (đối với cấp độ nhật ký 4 "CẢNH BÁO" trong lược đồ ưu tiên nhật ký hệ thống), theo kiểu tương tự như printk()hệ thống cấp của nhân Linux . Để biết chi tiết, hãy xem sd-daemon(3)systemd.exec(5).

Để tìm hiểu thêm, hãy đọc toàn bộ man 7 daemon.


11

Bạn không thể tạo một tiến trình trong linux mà không thể bị giết. Người dùng root (uid = 0) có thể gửi tín hiệu đến một tiến trình và có hai tín hiệu không thể bắt được, SIGKILL = 9, SIGSTOP = 19. Và các tín hiệu khác (khi chưa được ghi nhớ) cũng có thể dẫn đến kết thúc quá trình.

Bạn có thể muốn một hàm daemonize tổng quát hơn, nơi bạn có thể chỉ định tên cho chương trình / daemon của mình và đường dẫn để chạy chương trình của bạn (có thể là "/" hoặc "/ tmp"). Bạn cũng có thể muốn cung cấp (các) tệp cho stderr và stdout (và có thể là một đường dẫn điều khiển sử dụng stdin).

Dưới đây là những thứ cần thiết bao gồm:

#include <stdio.h>    //printf(3)
#include <stdlib.h>   //exit(3)
#include <unistd.h>   //fork(3), chdir(3), sysconf(3)
#include <signal.h>   //signal(3)
#include <sys/stat.h> //umask(3)
#include <syslog.h>   //syslog(3), openlog(3), closelog(3)

Và đây là một chức năng tổng quát hơn,

int
daemonize(char* name, char* path, char* outfile, char* errfile, char* infile )
{
    if(!path) { path="/"; }
    if(!name) { name="medaemon"; }
    if(!infile) { infile="/dev/null"; }
    if(!outfile) { outfile="/dev/null"; }
    if(!errfile) { errfile="/dev/null"; }
    //printf("%s %s %s %s\n",name,path,outfile,infile);
    pid_t child;
    //fork, detach from process group leader
    if( (child=fork())<0 ) { //failed fork
        fprintf(stderr,"error: failed fork\n");
        exit(EXIT_FAILURE);
    }
    if (child>0) { //parent
        exit(EXIT_SUCCESS);
    }
    if( setsid()<0 ) { //failed to become session leader
        fprintf(stderr,"error: failed setsid\n");
        exit(EXIT_FAILURE);
    }

    //catch/ignore signals
    signal(SIGCHLD,SIG_IGN);
    signal(SIGHUP,SIG_IGN);

    //fork second time
    if ( (child=fork())<0) { //failed fork
        fprintf(stderr,"error: failed fork\n");
        exit(EXIT_FAILURE);
    }
    if( child>0 ) { //parent
        exit(EXIT_SUCCESS);
    }

    //new file permissions
    umask(0);
    //change to path directory
    chdir(path);

    //Close all open file descriptors
    int fd;
    for( fd=sysconf(_SC_OPEN_MAX); fd>0; --fd )
    {
        close(fd);
    }

    //reopen stdin, stdout, stderr
    stdin=fopen(infile,"r");   //fd=0
    stdout=fopen(outfile,"w+");  //fd=1
    stderr=fopen(errfile,"w+");  //fd=2

    //open syslog
    openlog(name,LOG_PID,LOG_DAEMON);
    return(0);
}

Đây là một chương trình mẫu, nó sẽ trở thành một daemon, treo xung quanh và sau đó rời đi.

int
main()
{
    int res;
    int ttl=120;
    int delay=5;
    if( (res=daemonize("mydaemon","/tmp",NULL,NULL,NULL)) != 0 ) {
        fprintf(stderr,"error: daemonize failed\n");
        exit(EXIT_FAILURE);
    }
    while( ttl>0 ) {
        //daemon code here
        syslog(LOG_NOTICE,"daemon ttl %d",ttl);
        sleep(delay);
        ttl-=delay;
    }
    syslog(LOG_NOTICE,"daemon ttl expired");
    closelog();
    return(EXIT_SUCCESS);
}

Lưu ý rằng SIG_IGN chỉ ra để bắt và bỏ qua tín hiệu. Bạn có thể xây dựng một trình xử lý tín hiệu có thể ghi lại quá trình nhận tín hiệu và đặt các cờ (chẳng hạn như cờ để chỉ báo tắt máy nhanh).


8

Hãy thử sử dụng daemonchức năng:

#include <unistd.h>

int daemon(int nochdir, int noclose);

Từ trang người đàn ông :

Hàm daemon () dành cho các chương trình muốn tự tách khỏi thiết bị đầu cuối điều khiển và chạy ở chế độ nền dưới dạng các trình nền hệ thống.

Nếu nochdir bằng 0, daemon () thay đổi thư mục làm việc hiện tại của quá trình gọi thành thư mục gốc ("/"); nếu không, thư mục làm việc hiện tại được giữ nguyên.

Nếu noclose bằng 0, daemon () chuyển hướng đầu vào tiêu chuẩn, đầu ra tiêu chuẩn và lỗi tiêu chuẩn thành / dev / null; nếu không, không có thay đổi nào được thực hiện đối với các bộ mô tả tệp này.


2
Lưu ý rằng daemon(7)thủ công đề cập đến các bước để tạo daemon và cảnh báo rằng: Không daemon()nên sử dụng hàm BSD , vì nó chỉ triển khai một tập hợp con của các bước này. daemonchức năng lần đầu tiên xuất hiện trong 4.4BSDkhông tương thích với POSIX .
patryk.beza

2
Cũng lưu ý rằng cảnh báo về việc sử dụng daemon () nằm trong phần SysV kiểu cũ của trang người dùng daemon (7) . Việc sử dụng daemon () không được khuyến khích đối với systemd.
Greg McPherran

7

Tôi có thể dừng lại ở yêu cầu đầu tiên "Một daemon không thể dừng lại ..."

Không thể bạn của tôi; tuy nhiên, bạn có thể đạt được điều tương tự với một công cụ tốt hơn nhiều, mô-đun hạt nhân.

http://www.infoq.com/articles/inotify-linux-file-system-event-monitoring

Tất cả daemon có thể bị dừng lại. Một số dễ dàng dừng lại hơn những người khác. Ngay cả một cặp daemon với đối tác đang bị giữ lại, có thể dừng lại đối tác nếu bị mất. Bạn chỉ cần làm việc chăm chỉ hơn một chút.


7
Tôi nghĩ rằng bằng cách nói "Một daemon không thể dừng lại", tác giả thực sự có nghĩa là daemon luôn chạy nền khi phiên kết thúc.
FaceBro

6

Nếu ứng dụng của bạn là một trong những:

{
  ".sh": "bash",
  ".py": "python",
  ".rb": "ruby",
  ".coffee" : "coffee",
  ".php": "php",
  ".pl" : "perl",
  ".js" : "node"
}

và bạn không bận tâm đến sự phụ thuộc NodeJS, sau đó cài đặt NodeJS và sau đó:

npm install -g pm2

pm2 start yourapp.yourext --name "fred" # where .yourext is one of the above

pm2 start yourapp.yourext -i 0 --name "fred" # run your app on all cores

pm2 list

Để giữ cho tất cả các ứng dụng chạy khi khởi động lại (và daemonise pm2):

pm2 startup

pm2 save

Bây giờ bạn có thể:

service pm2 stop|restart|start|status

(cũng dễ dàng cho phép bạn theo dõi các thay đổi mã trong thư mục ứng dụng của bạn và tự động khởi động lại quy trình ứng dụng khi xảy ra thay đổi mã)


2
Này không có gì để làm với C.
Melpomene

4
Tôi đánh giá cao có một thẻ C. Tuy nhiên, OP không đề cập đến yêu cầu liên quan đến C trong câu hỏi. Tiêu đề là tạo ra một con quỷ trong linux. Câu trả lời này thỏa mãn điều đó.
danday74,

1
Oh bạn nói đúng. Nó được gắn thẻ C, nhưng yêu cầu thực tế là C ++ (bằng chứng là mã của OP và bài viết được liên kết).
melpomene

3

Bằng cách gọi fork (), bạn đã tạo một tiến trình con. Nếu fork thành công (fork trả về một PID khác 0) thì việc thực thi sẽ tiếp tục từ thời điểm này từ bên trong process con. Trong trường hợp này, chúng tôi muốn thoát khỏi quy trình mẹ một cách dễ dàng và sau đó tiếp tục công việc của chúng tôi trong quy trình con.

Có thể điều này sẽ hữu ích: http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html


2

Daemon chỉ là một tiến trình ở chế độ nền. Nếu bạn muốn khởi động chương trình của mình khi HĐH khởi động, trên linux, bạn thêm lệnh start của mình vào /etc/rc.d/rc.local (chạy sau tất cả các tập lệnh khác) hoặc /etc/startup.sh

Trên windows, bạn tạo một dịch vụ, đăng ký dịch vụ và sau đó đặt nó tự động khởi động khi khởi động trong bảng quản trị -> dịch vụ.


1
Cảm ơn. Vì vậy, không có sự khác biệt giữa một "daemon" và một chương trình bình thường? Tôi không muốn nó được đóng lại một cách dễ dàng.
chrisMe,

1
Không, daemon chỉ là một quá trình nền. Cụ thể hơn, bạn tách từ cha mẹ, chạy tiến trình con và chấm dứt cha mẹ (để không có quyền truy cập đầu cuối vào chương trình). đó của n ot relaly cần thiết mặc dù là một "daemon": en.wikipedia.org/wiki/Daemon_(computing)
Magn3s1um

1

Mẫu Daemon

Tôi đã viết một mẫu daemon theo daemon kiểu mới: liên kết

Bạn có thể tìm thấy toàn bộ mã mẫu trên GitHub: tại đây

Main.cpp

// This function will be called when the daemon receive a SIGHUP signal.
void reload() {
    LOG_INFO("Reload function called.");
}

int main(int argc, char **argv) {
    // The Daemon class is a singleton to avoid be instantiate more than once
    Daemon& daemon = Daemon::instance();
    // Set the reload function to be called in case of receiving a SIGHUP signal
    daemon.setReloadFunction(reload);
    // Daemon main loop
    int count = 0;
    while(daemon.IsRunning()) {
        LOG_DEBUG("Count: ", count++);
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    LOG_INFO("The daemon process ended gracefully.");
}

Daemon.hpp

class Daemon {
    public:

    static Daemon& instance() {
        static Daemon instance;
        return instance;
    }

    void setReloadFunction(std::function<void()> func);

    bool IsRunning();

    private:

    std::function<void()> m_reloadFunc;
    bool m_isRunning;
    bool m_reload;

    Daemon();
    Daemon(Daemon const&) = delete;
    void operator=(Daemon const&) = delete;

    void Reload();

    static void signalHandler(int signal);
};

Daemon.cpp

Daemon::Daemon() {
    m_isRunning = true;
    m_reload = false;
    signal(SIGINT, Daemon::signalHandler);
    signal(SIGTERM, Daemon::signalHandler);
    signal(SIGHUP, Daemon::signalHandler);
}

void Daemon::setReloadFunction(std::function<void()> func) {
    m_reloadFunc = func;
}

bool Daemon::IsRunning() {
    if (m_reload) {
        m_reload = false;
        m_reloadFunc();
    }
    return m_isRunning;
}

void Daemon::signalHandler(int signal) {
    LOG_INFO("Interrup signal number [", signal,"] recived.");
    switch(signal) {
        case SIGINT:
        case SIGTERM: {
            Daemon::instance().m_isRunning = false;
            break;
        }
        case SIGHUP: {
            Daemon::instance().m_reload = true;
            break;
        }
    }
}

daemon-template.service

[Unit]
Description=Simple daemon template
After=network.taget

[Service]
Type=simple
ExecStart=/usr/bin/daemon-template --conf_file /etc/daemon-template/daemon-tenplate.conf
ExecReload=/bin/kill -HUP $MAINPID
User=root
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=daemon-template

[Install]
WantedBy=multi-user.target
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.