Forum: D Programlama Dili RSS
arkaplanda servis olarak çalıştırma
darkofpain #1
Üye Ağu 2013 tarihinden beri · 58 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: arkaplanda servis olarak çalıştırma
Merhaba,

yaptığım uygulamayı normalde çift tıkladığımız zaman terminalde acılır ve program calışır ancak terminali kapattığımız zaman programda sonlanır.

yaptığım uygulamayı ./bin klasörüne yerleştirdim terminalede program yazdığım zaman çalışıyor ancak yine terminali kapatınca uygulama kapanıyor bu yüzden yaptığım uygulamayı program -start dediğim paylaşmasını ve arkaplanda çalışmasını istiyorum terminali kapatsam dahi program çalışacak.

ancak kapatmam gerektiğinde terminale program -stop dediğimde programı sonlandırıp kapatacak

bu olayı nasıl yapabilirim arkadaşlar.
acehreli (Moderatör) #2
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanılmıyorsam bu konu Windows'da Windows Service diye geçiyor:

  http://msdn.microsoft.com/en-us/library/9k985bc9.aspx

Linux dünyasında da böyle programlara daemon deniyor. Google'da bulduğumuz C örneklerini herhalde D'ye çevirerek deneyebiliriz.

Ali
darkofpain #3
Üye Ağu 2013 tarihinden beri · 58 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
valla c ile ilgili örnek bulamadım o yüzden d ile nasıl olur bilemiyorum da bu işin bu kadar zor olması tuhaf.
acehreli (Moderatör) #4
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Ben "linux daemon in c" diye aratıyorum. Google sonuçları herkese aynı göstermiyor diye bana çıkan bir örneğin sonundaki iki referans sayfayı göstereyim:

  http://www.netzmafia.de/skripten/unix/linux-daemon-howto.h…

  http://blog.emptycrate.com/node/219

Zaman bulunca ben de bir örnek yazarım.

bu işin bu kadar zor olması tuhaf

Kimse zaman ayırıp kolaylaştıran bir çözüm getirmediği için öyle. Bence servisleştir() (veya daemonize()) diyeceğimiz bu işlevi sen yazacaksın. ;)


Ali
acehreli (Moderatör) #5
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Oradaki bağlantıdan öğrendim ve aşağıdaki programı yazdım. Ana program servisin program kimliğini yazdırıyor ve sonlanıyor:

İşçi başlatıldı: 20713

İşçi program bağımsızca SIGTERM (15) sinyalini alana kadar çalışmaya devam ediyor. (O sinyali göndermek için neden root olunması gerektiğinden emin değilim ama sudo yazmazsam bende sonlanmıyor.):

$ sudo kill 15 20713

İşçi program kayıtlarını /tmp/Servis_denemesi_kayitlari diye bir dosyaya yazıyor:

$ cat /tmp/Servis_denemesi_kayitlari
Servis oldum
Servis döngüsüne giriyorum
0
1
2
Servis döngüsünden çıktım


Program:

import std.stdio;
import std.exception;
import core.sys.posix.unistd;
import core.sys.posix.signal;
import core.sys.posix.sys.stat;
import core.thread;
 
bool devam_mı = true;
 
int main()
{
    pid_t kimlik = fork();
 
    if (kimlik < 0) {
        stderr.writeln("HATA: fork başarısız");
        return 1;
    }
 
    if (kimlik > 0) {
        // Bu durumda sahip programda devam etmekteyiz. Başka bir şey
        // yapmamıza gerek yok; sahip sonlanmalı.
        writeln("İşçi başlatıldı: ", kimlik);
 
        // DÜZELTME: Bu satır araya sıkışmış. :) Ona tabii ki gerek yok.
        // Thread.sleep(30.seconds);
 
    } else {
        // Bu durumda işçi programdayız. Bu programı servis (daemon) haline
        // getirmemiz gerekiyor.
        File kayıt = servisiHazırla();
        servisiİşlet(kayıt);
    }
 
    return 0;
}
 
extern(C) void sonlanmaSinyali(int) nothrow @system
{
    devam_mı = false;
}
 
File servisiHazırla()
{
    // Dosyalara yazabilmeyi sağla
    umask(0);
 
    // Servis kayıt (log) dosyasını aç
    auto kayıt = File("/tmp/Servis_denemesi_kayitlari", "w");
 
    // Sahipsiz (orphan) bir program olmayalım diye işletim sistemi
    // çekirdeğinden bir oturum numarası ediniyoruz.
    pid_t oturumNumarası = setsid();
    if (oturumNumarası < 0) {
        enum mesaj = "HATA: Oturum numarası (SID) edinemedim";
        kayıt.writeln(mesaj);
        throw new Exception(mesaj);
    }
 
    // Programın geçerli bir klasör içinde çalışmakta olduğunu garanti
    // et. Linux standardına göre var olduğundan kesinlikle emin olduğumu
    // klasör / (root) klasörüdür.
    int hata = chdir("/");
    if (hata) {
        enum mesaj = "HATA: Çalışma klasörünü ayarlayamadım";
        kayıt.writeln(mesaj);
        throw new Exception(mesaj);
    }
 
    // Hem konsolu kullanamayacağımız için hem de güvenlik riski nedeniyle üç
    // standart akımı kapatmalıyız.
    stdin.close();
    stdout.close();
    stderr.close();
 
    // Sonlanma sinyaline hazırlan
    signal(SIGTERM, &sonlanmaSinyali);
 
    kayıt.writeln("Servis oldum");
 
    kayıt.flush();
    return kayıt;
}
 
void servisiİşlet(File kayıt)
{
    kayıt.writeln("Servis döngüsüne giriyorum");
 
    // Servisin ana döngüsü
    for (size_t sayaç = 0; devam_mı; ++sayaç) {
        kayıt.writeln(sayaç);
        kayıt.flush();
        Thread.sleep(1.seconds);
    }
 
    kayıt.writeln("Servis döngüsünden çıktım");
}
Ali
Bu mesaj acehreli tarafından değiştirildi; zaman: 2013-10-11, 23:53.
acehreli (Moderatör) #6
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
acehreli on 2013-10-11, 19:21:
İşçi program bağımsızca SIGTERM (15) sinyalini alana kadar çalışmaya devam ediyor. (O sinyali göndermek için neden root olunması gerektiğinden emin değilim ama sudo yazmazsam bende sonlanmıyor.):

$ sudo kill 15 20713

Ha ha! Yanlış yazmışım. 15 numaralı sinyali göndereceğim diye yanlışlıkla 15 numaralı programı sonlandırmışım! :) Şöyle olmalı:

$ kill -s 15 20713

Ali
acehreli (Moderatör) #7
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Bu kodu sınıf halinde düzenledim. Servis olmak isteyen bir program Servis sınıfından türetilmeli ve işlet() işlevini tanımlamalı.

import std.stdio;
import std.exception;
import core.sys.posix.unistd;
import core.sys.posix.signal;
import core.sys.posix.sys.stat;
import core.thread;
 
// ========== Bu bölüm servis.d modülü ==========
bool devam_mı = true;
 
extern(C) void sonlanmaSinyaliAlındı(int) nothrow @system
{
    devam_mı = false;
}
 
// Not: Aynı programda birden fazla Servis nesnesinin çalışabileceğini
//      sanmıyorum. Eğer gerçekten öyleyse bunun önlenmesi de gerekir.
 
class Servis
{
    string kayıtDosyasıİsmi;
    File kayıt;
 
    this(string kayıtDosyasıİsmi)
    {
        this.kayıtDosyasıİsmi = kayıtDosyasıİsmi;
    }
 
    pid_t başla()
    {
        pid_t kimlik = fork();
        enforce (kimlik >= 0, "fork başarısız");
 
        if (kimlik > 0) {
            // Bu durumda sahip programda devam etmekteyiz. Başka bir şey
            // yapmamıza gerek yok.
 
        } else {
            // Bu durumda işçi programdayız. Bu programı servis (daemon)
            // haline getirmemiz gerekiyor.
            hazırlan();
 
            mesajEkle("Servis işlemlerini başlatıyorum");
            işlet();
            mesajEkle("Servis işlemleri bitti");
        }
 
        return kimlik;
    }
 
    void hazırlan()
    {
        // Dosyalara yazabilmeyi sağla.
        umask(0);
 
        // Servis kayıt (log) dosyasını aç; dış dünyayla tek iletişimimiz bu
        // olacak.
        kayıt = File(kayıtDosyasıİsmi, "w");
 
        void denetle(bool koşul, string mesaj)
        {
            if (!koşul) {
                mesajEkle(mesaj);
                throw new Exception(mesaj);
            }
        }
 
        // Sahipsiz (orphan) bir program olmayalım diye işletim sistemi
        // çekirdeğinden bir oturum numarası edin.
        pid_t oturumNumarası = setsid();
        denetle(oturumNumarası >= 0, "Oturum numarası (SID) edinemedim");
 
        // Programın geçerli bir klasör içinde çalışmakta olduğunu garanti
        // et. Linux standardına göre var olduğundan kesinlikle emin olunan
        // klasör / (root) klasörüdür.
        int hata = chdir("/");
        denetle(hata == 0, "Çalışma klasörünü değiştiremedim");
 
        // Hem konsolu kullanamayacağımız için hem de güvenlik riski nedeniyle
        // üç standart akımı kapatmalıyız.
        stdin.close();
        stdout.close();
        stderr.close();
 
        // Sonlanma sinyalini almaya hazırlan.
        signal(SIGTERM, &sonlanmaSinyaliAlındı);
 
        mesajEkle("Servis oldum");
    }
 
    void mesajEkle(T...)(T mesajlar)
    {
        kayıt.writeln(mesajlar);
        kayıt.flush();
    }
 
    // Servis olmak isteyen bir programın yapması gereken, Servis'ten türetmek
    // ve soyut işlet() işlevinin o servise uygun bir tanımını vermektir.
    abstract void işlet();
}
 
// ========== Bundan sonrası da o modülü kullanan örnek bir program ==========
 
// Bir servis tanımlıyoruz
class BenimServis : Servis
{
    this()
    {
        // Yapmamız gereken, üst sınıfın istediği kayıt dosyası ismini vermek
        super("/tmp/Servis_denemesi_kayitlari");
    }
 
    // Bir de kendi işimize uygun bir işlet() işlevi yazmak
    override void işlet()
    {
        // Bu, servisin ana döngüsü. 'devam_mı' değişkeni servis.d modülü
        // tarafından sunuluyor.
        for (size_t sayaç = 0; devam_mı; ++sayaç) {
            mesajEkle(sayaç);
            Thread.sleep(1.seconds);
        }
    }
}
 
void main()
{
    auto servis = new BenimServis();
 
    pid_t işçiKimliği = servis.başla();
    writeln("İşçi başlatıldı: ", işçiKimliği);
}
Ali
acehreli (Moderatör) #8
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
// Not: Aynı programda birden fazla Servis nesnesinin çalışabileceğini
//      sanmıyorum. Eğer gerçekten öyleyse bunun önlenmesi de gerekir. 

Bu konudaki deneyimsizliğimi sergilemeye devam ediyorum. :) Yukarıda söylediğim doğru değil çünkü her fork'ta bağımsız bir program ortaya çıkıyor. Dolayısıyla, her birisinin devam_mı değişkenleri de bağımsız. Yani, aynı program birden fazla Servis oluşturabilir. (Sanırım. :-p)

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-19, 08:14:00 (UTC -08:00)