Linux'ta bir arka plan programı oluşturmak


110

Linux'ta, durdurulamayan ve dosya sistemi değişikliklerini izleyen bir arka plan programı eklemek istiyorum. Herhangi bir değişiklik tespit edilirse, başlatıldığı konsola giden yolu artı bir yeni satır yazmalıdır.

Dosya sistemini değiştiren kodu zaten hazır bulunduruyorum ama nasıl bir arka plan programı yaratacağımı çözemiyorum.

Kodum buradan: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

Çataldan sonra ne yapmalı?

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;
}



POSIX uyumluluğuna ihtiyacınız yoksa inotifyAPI ile ilgilenebilirsiniz . Bkz: inotify_init, inotify_add_watch, inotify_rm_watch.
patryk.beza

Yanıtlar:


216

Linux'ta, durdurulamayan ve dosya sistemi değişikliklerini izleyen bir arka plan programı eklemek istiyorum. Herhangi bir değişiklik tespit edilirse, başlatıldığı konsola giden yolu + bir satır arası yazmalıdır.

Daemonlar arka planda çalışır ve (genellikle ...) bir TTY'ye ait değildir, bu yüzden stdout / stderr'i muhtemelen istediğiniz şekilde kullanamazsınız. Genellikle bir syslog arka plan programı ( syslogd ), iletileri dosyalara günlüğe kaydetmek için kullanılır (hata ayıklama, hata, ...).

Bunun yanı sıra, bir süreci daemonize etmek için gerekli birkaç adım vardır .


Doğru hatırlıyorsam bu adımlar şunlardır:

  • çatal ebeveyn sürecini & çatallaşma başarılı olup olmadığını o sonlandırmak edelim. -> Üst süreç sona erdiğinden, alt süreç artık arka planda çalışıyor.
  • setsid - Yeni bir oturum oluşturun. Çağıran süreç, yeni oturumun lideri ve yeni süreç grubunun süreç grubu lideri olur. İşlem artık kontrol terminalinden (CTTY) ayrılmıştır.
  • Sinyalleri yakala - Sinyalleri yok sayın ve / veya işleyin.
  • tekrar çatallayın ve oturum liderlik sürecinden kurtulmanızı sağlamak için ana sürecin sonlanmasına izin verin. (Yalnızca oturum liderleri tekrar TTY alabilir.)
  • chdir - Arka plan programının çalışma dizinini değiştirin.
  • umask - Dosya modu maskesini arka plan programının ihtiyaçlarına göre değiştirin.
  • kapat - Üst işlemden devralınabilecek tüm açık dosya tanımlayıcılarını kapatın.

Size bir başlangıç ​​noktası vermek için: Temel adımları gösteren bu iskelet koda bakın. Bu kod artık GitHub'da da çatallanabilir: Linux arka plan programının temel iskeleti

/*
 * 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;
}


  • Kodu derleyin: gcc -o firstdaemon daemonize.c
  • Arka planı başlatın: ./firstdaemon
  • Her şeyin düzgün çalışıp çalışmadığını kontrol edin: ps -xj | grep firstdaemon

  • Çıktı buna benzer olmalıdır:

+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
| PPID | PID | PGID | SID | TTY | TPGID | STAT | UID | ZAMAN | CMD |
+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
| 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ |
+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +

Burada görmeniz gereken şey:

  • Arka plan programının kontrol terminali yok ( TTY =? )
  • Üst süreç kimliği ( PPID ) 1'dir (başlatma işlemi)
  • PID! = SID bizim süreç oturum lideri olmadığı anlamına gelir
    (çünkü ikinci fork ())
  • PID! = SID olduğundan, sürecimiz bir TTY'nin kontrolünü tekrar alamaz

Sistem günlüğünü okumak:

  • Sistem günlüğü dosyanızı bulun. Benimki burada:/var/log/syslog
  • Yapın: grep firstdaemon /var/log/syslog

  • Çıktı buna benzer olmalıdır:

  firstdaemon [3387]: İlk arka plan programı başlatıldı.
  firstdaemon [3387]: İlk arka plan programı sona erdirildi.


Bir not: Gerçekte, bir sinyal işleyici uygulamak ve günlük kaydını düzgün bir şekilde ayarlamak (Dosyalar, günlük seviyeleri ...) isteyeceksiniz.

Daha fazla okuma:


Vay, teşekkürler! Bu harika. Yani, kodumu while döngüsüne koymalıyım ve bu mu?
chrisMe

Temelde evet. Ancak bu kod sadece bir örnektir. Tamamen bir arka plan programı süreci kullanarak neyi başarmak istediğinize bağlıdır . Bu yanıtı da okuduğunuzdan emin olun: @Edwin
Pascal Werkl

1
İkincisi yerine fork()neden sadece kullanmıyoruz setsid()?
Chimera

1
Not bu fonksiyon sinyalleri kontrol etmek için daha kapsamlı ve güvenilir bir mekanizma sağlar; yerine yeni uygulamalar kullanılmalıdır . sigaction()sigaction()signal()
patryk.beza

4
İzleyicilere bu yöntemin "eski" yol olduğu unutulmamalıdır. Bir arka plan programı oluşturmanın yeni önerilen yolu, şu adreste bulunan "yeni stil arka plan programı" dır : 0pointer.de/public/systemd-man/daemon.html#New-Style%20Daemons veya
Starlord

30

man 7 daemonarka plan programının nasıl oluşturulacağını ayrıntılı olarak açıklar. Cevabım bu kılavuzdan sadece bir alıntıdır.

En az iki tür arka plan programı vardır:

  1. geleneksel SysV arka plan yordamları ( eski tarz ),
  2. systemd arka plan programları ( yeni stil ).

SysV Daemonları

Geleneksel SysV arka plan programıyla ilgileniyorsanız , aşağıdaki adımları uygulamalısınız :

  1. Standart giriş , çıkış ve hata dışındaki tüm açık dosya tanımlayıcılarını kapatın (yani, ilk üç dosya tanımlayıcısı 0, 1, 2). Bu, yanlışlıkla aktarılan hiçbir dosya tanımlayıcısının daemon sürecinde kalmamasını sağlar. Linux'ta, bu en iyi şekilde /proc/self/fd, dosya tanımlayıcısı 3'ten getrlimit()for tarafından döndürülen değere yinelenerek yinelenerek uygulanır RLIMIT_NOFILE.
  2. Tüm sinyal işleyicileri varsayılan değerlerine sıfırlayın . Bu, en iyi, mevcut sinyalleri sınırına kadar yineleyerek _NSIGve sıfırlayarak yapılır SIG_DFL.
  3. Sinyal maskesini kullanarak sıfırlayın sigprocmask().
  4. Arka plan programı çalışma zamanını olumsuz etkileyebilecek ortam değişkenlerini kaldırarak veya sıfırlayarak ortam bloğunu temizleyin.
  5. fork()Bir arka plan işlemi oluşturmak için arayın .
  6. Çocukta setsid()herhangi bir terminalden ayrılmak için arayın ve bağımsız bir oturum oluşturun .
  7. Çocukta, fork()arka plan programının bir uçbirimi bir daha asla yeniden edinemeyeceğinden emin olmak için tekrar arayın .
  8. exit()İlk çocuğu arayın , böylece sadece ikinci çocuk (gerçek arka plan programı süreci) ortalıkta kalsın. Bu, tüm arka plan programlarının olması gerektiği gibi, arka plan programı sürecinin init / PID 1'e yeniden eşlenmesini sağlar.
  9. Arka plan programı sürecinde, /dev/nullstandart giriş , çıkış ve hataya bağlanın .
  10. Daemon süreçte, reset umaskdosyası modları geçirilen böylece, 0 open(), mkdir()doğrudan oluşturulan dosyaların ve dizinlerin erişim modunu kontrol suchlike.
  11. Arka plan programı sürecinde, arka plan programının bağlanma noktalarının kaldırılmasını istem dışı olarak engellemesini önlemek için geçerli dizini kök dizine ( ) değiştirin/ .
  12. Artalan süreci sürecinde, daemon'un birden fazla kez başlatılamayacağından emin olmak için, arka plan programı PID'sini (döndürdüğü şekliyle getpid()) bir PID dosyasına yazın /run/foobar.pid(varsayımsal bir arka plan programı "foobar" için). Bu, yarışsız bir şekilde uygulanmalıdır, böylece PID dosyası yalnızca daha önce PID dosyasında saklanan PID'nin artık mevcut olmadığı veya yabancı bir sürece ait olduğu doğrulandığında güncellenir.
  13. Arka plan programı sürecinde, mümkünse ve uygulanabilirse ayrıcalıkları kaldırın.
  14. Arka plan programı sürecinden, başlatmanın tamamlandığına dair orijinal sürecin başladığını bildirin. Bu, adsız bir kanal veya ilkinden önce oluşturulan fork()ve dolayısıyla hem orijinal hem de arka plan programı sürecinde mevcut olan benzer bir iletişim kanalı aracılığıyla uygulanabilir .
  15. Aramak exit()Orijinal süreci . Arka plan programı başlatan süreç, bunun başlatma tamamlandıktan ve tüm dış iletişim kanalları kurulduktan ve erişilebilir olduktan sonraexit() gerçekleşeceğine güvenebilmelidir .

Bu uyarıyı not edin:

BSD daemon() işlevi olmamalıdır sadece bir uygulayan olarak kullanılabilir alt kümesini bu adımların.

SysV sistemleriyle uyumluluk sağlaması gereken bir arka plan programı, yukarıda belirtilen şemayı uygulamalıdır. Ancak, hata ayıklamayı kolaylaştırmak ve systemd kullanarak sistemlere entegrasyonu basitleştirmek için bu davranışı isteğe bağlı ve bir komut satırı argümanı aracılığıyla yapılandırılabilir hale getirmeniz önerilir.

Bunu not et daemon()POSIX uyumlu olmadığını .


Yeni Tarz Daemonlar

Yeni tarz arka plan yordamları için aşağıdaki adımlar önerilir:

  1. Eğer alınırsa SIGTERM, arka plan programını kapatın ve temiz bir şekilde çıkın.
  2. Eğer SIGHUP , bu geçerliyse yapılandırma dosyalarını yeniden yükleyin.
  3. Başlatma sistemi tarafından hizmet hatalarını ve sorunlarını tespit etmek için kullanıldığından, ana arka plan programı işleminden doğru bir çıkış kodu sağlayın. Çıkış kodu şemasına uymanız önerilir.SysV başlatma komut dosyaları için LSB önerilerinde önerilir .
  4. Mümkünse ve uygulanabilirse, arka planın kontrol arayüzünü D-Bus IPC sistemi ve başlatmanın son adımı olarak bir veri yolu adı alın.
  5. Systemd'ye entegrasyon için , arka plan programının başlatılması, durdurulması ve başka şekilde bakımı hakkında bilgi taşıyan bir .service birimi dosyası sağlayın . Görmeksystemd.service(5) için bakın.
  6. Mümkün olduğunca, arka plan programının dosyalara, hizmetlere ve diğer kaynaklara erişimini sınırlamak için init sisteminin işlevselliğine güvenin, yani systemd söz konusu olduğunda, kendinizinkini uygulamak yerine systemd'nin kaynak sınır kontrolüne güvenin, systemd'nin ayrıcalık bırakmasına güvenin daemon'da uygulamak yerine kod ve benzeri. Görmeksystemd.exec(5)Mevcut kontroller için .
  7. Eğer D-Bus kullanılır, D-otobüs servisi aktivasyonu sağlayarak sizin cini otobüsü ile aktive edilebilen hale yapılandırma dosyası . Bunun birçok avantajı vardır: daemonunuz istek üzerine tembel olarak başlatılabilir; bunu gerektiren diğer arka plan yordamlarına paralel olarak başlatılabilir - bu da paralelleştirme ve önyükleme hızını en üst düzeye çıkarır ; Veriyolu kuyrukları etkinleştirilebilir hizmetler için istediği için, arıza durumunda herhangi bir veri yolu talebini kaybetmeden yeniden başlatılabilir. Ayrıntılar için aşağıya bakın.
  8. Senin cin bir soket vasıtasıyla diğer yerel süreçler veya uzak müşterilerine hizmet vermektedir, yapılmalıdır soket ile aktive edilebilen düzeni aşağıdaki işaret altında . D-Bus aktivasyonu gibi, bu, hizmetlerin isteğe bağlı olarak başlatılmasını sağlar ve hizmet başlangıcında gelişmiş paralelleştirme sağlar. Ayrıca, durumsuz protokoller için (syslog, DNS gibi), soket tabanlı aktivasyonu uygulayan bir arka plan programı, tek bir isteği kaybetmeden yeniden başlatılabilir. Ayrıntılar için aşağıya bakın.
  9. Mümkünse, bir arka plan programı başlatma sistemini sd_notify(3)arabirim aracılığıyla başlatmanın tamamlanması veya durum güncellemeleri hakkında bilgilendirmelidir .
  10. syslog()Çağrıyı doğrudan sistem syslog hizmetinde oturum açmak için kullanmak yerine, yeni tarz bir arka plan programı, basitçe standart hatada oturum açmayı seçebilir ve fprintf()bu daha sonra ilk sistem tarafından syslog'a iletilir. Günlük seviyeleri gerekliyse, bunlar, Linux çekirdeğinin printk()seviye sistemi ile benzer bir stil izlenerek, "<4>" gibi dizelerle (syslog öncelik düzeninde günlük seviyesi 4 "UYARI" için) ayrı günlük satırlarının önüne eklenerek kodlanabilir . Ayrıntılar için bkz. sd-daemon(3)Ve systemd.exec(5).

Daha fazlasını öğrenmek için tamamını okuyun man 7 daemon.


11

Linux'ta öldürülemeyen bir süreç oluşturamazsınız. Kök kullanıcı (uid = 0) bir işleme sinyal gönderebilir ve yakalanamayan iki sinyal vardır, SIGKILL = 9, SIGSTOP = 19. Ve diğer sinyaller (yakalanmadığında) da sürecin sonlandırılmasına neden olabilir.

Programınız / arka plan programınız için bir isim ve programınızı çalıştırmak için bir yol (belki "/" veya "/ tmp") belirtebileceğiniz daha genel bir daemonize işlevi isteyebilirsiniz. Ayrıca stderr ve stdout (ve muhtemelen stdin kullanan bir kontrol yolu) için dosya (lar) da sağlamak isteyebilirsiniz.

İşte gerekli içerir:

#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)

Ve işte daha genel bir işlev,

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);
}

İşte bir arka plan programı haline gelen, etrafta dolanan ve sonra ayrılan örnek bir program.

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);
}

SIG_IGN'ın sinyali yakalamayı ve yok saymayı gösterdiğine dikkat edin. Sinyal alımını günlüğe kaydedebilen ve bayraklar (nazikçe kapatmayı gösteren bir bayrak gibi) ayarlayabilen bir sinyal işleyici oluşturabilirsiniz.


8

Şu daemonişlevi kullanmayı deneyin :

#include <unistd.h>

int daemon(int nochdir, int noclose);

Gönderen adam sayfası :

Daemon () işlevi, kendilerini kontrol terminalinden ayırmak ve arka planda sistem arka plan programı olarak çalıştırmak isteyen programlar içindir.

Nochdir sıfır ise, daemon () çağıran sürecin geçerli çalışma dizinini kök dizine ("/") değiştirir; aksi takdirde, geçerli çalışma dizini değiştirilmeden bırakılır.

Noclose sıfır ise, daemon () standart girişi, standart çıkışı ve standart hatayı / dev / null'a yönlendirir; aksi takdirde, bu dosya tanımlayıcılarda herhangi bir değişiklik yapılmaz.


2
Not o daemon(7)manuel Daemon oluşturmak için adımları bahseder ve konusunda uyarıyor: BSD daemon()bu adımlardan sadece bir alt kümesini uygulayan olarak işlev kullanılmamalıdır. daemonişlevi ilk olarak 4.4BSD'de ortaya çıktı ve POSIX uyumlu değil .
patryk.beza

2
Daemon () kullanımı hakkındaki uyarının daemon (7) kılavuz sayfasının eski stil SysV bölümünde olduğuna da dikkat edin . Daemon () kullanımı systemd için önerilmez.
Greg McPherran

7

İlk gereksinimde durdurabilirim " Durdurulamayan bir arka plan programı ..."

Mümkün değil dostum; ancak, aynısını çok daha iyi bir araçla, bir çekirdek modülüyle elde edebilirsiniz.

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

Tüm artalan süreçleri durdurulabilir. Bazıları diğerlerinden daha kolay durdurulur. Ortağı tutulan ve kaybedilirse ortağı yeniden canlandıran bir arka plan programı çifti bile durdurulabilir. Sadece biraz daha fazla çalışmalısın.


7
Yazarın aslında "Durdurulamayan bir arka plan programı" diyerek, oturum sonlandırıldığında arka planda çalıştığını kastettiğini düşünüyorum.
FaceBro

6

Uygulamanız şunlardan biriyse:

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

ve bir NodeJS bağımlılığına aldırış etmiyorsunuz, ardından NodeJS'yi yükleyin ve ardından:

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

Tüm uygulamaların yeniden başlatıldığında (ve pm2 arka plan programı) çalışmaya devam etmesini sağlamak için:

pm2 startup

pm2 save

Şimdi yapabilirsin:

service pm2 stop|restart|start|status

(ayrıca uygulama dizininizdeki kod değişikliklerini kolayca izlemenize ve bir kod değişikliği olduğunda uygulama sürecini otomatik olarak yeniden başlatmanıza olanak tanır)


2
Bunun C. ile ilgisi yok
melpomene

4
C etiketi olduğu için minnettarım. Ancak OP, söz konusu C ile ilgili bir gereklilikten bahsetmemektedir. Başlık, linux'ta bir iblis yaratıyor. Bu cevap bunu tatmin ediyor.
danday74

1
Oh, haklısın. C etiketli, ancak asıl gereksinim C ++ 'dır (OP'nin kodu ve bağlantılı makale tarafından kanıtlandığı gibi).
melpomene

3

Fork () 'u çağırarak bir çocuk süreç oluşturdunuz. Çatal başarılı olursa (çatal sıfırdan farklı bir PID döndürürse) yürütme, bu noktadan çocuk sürecin içinden devam edecektir. Bu durumda, ana süreçten zarif bir şekilde çıkmak ve ardından alt süreçteki çalışmamıza devam etmek istiyoruz.

Belki bu yardımcı olur: http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html


2

Arka planda bir arka plan programı yalnızca bir süreçtir. Linux'ta işletim sistemi başlatıldığında programınızı başlatmak istiyorsanız, başlatma komutunuzu /etc/rc.d/rc.local (diğer tüm komut dosyalarından sonra çalıştırın) veya /etc/startup.sh içine ekleyin.

Windows'ta, bir hizmet oluşturursunuz, hizmeti kaydedersiniz ve ardından, yönetim -> hizmetler panelinde önyükleme sırasında otomatik olarak başlayacak şekilde ayarlarsınız.


1
Teşekkürler. Öyleyse bir "arka plan programı" ile sadece normal bir Program arasında hiçbir fark yok mu? Kolay kapanmasını istemiyorum.
chrisMe

1
Hayır, bir arka plan programı yalnızca bir arka plan sürecidir. Daha spesifik olarak, bir ebeveynden çatallanırsınız, çocuk süreci çalıştırırsınız ve ebeveyni sonlandırırsınız (böylece programa terminal erişimi olmaz). bu bir "arka plan programı" olmasına rağmen gerekli değildir: en.wikipedia.org/wiki/Daemon_(computing)
Magn3s1um

1

Daemon Şablonu

Yeni stil arka plan programının ardından bir arka plan programı şablonu yazdım: bağlantı

Şablon kodunun tamamını GitHub'da bulabilirsiniz: burada

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.