[linux] daemon, sockety

0

Witam!

Napisałem właśnie program - daemona, który co 10 minut budzi się i wykonuje swoje zadania.

 while (1) {
           /***************************
            *       jakieś operacje         *
            ***************************/
           sleep(600);
    }

I teraz chciałbym rozbudować program o jedną właściwość - możliwość odpytywania daemona o wynik ostatnio przeprowadzonej operacji w każdej chwili. Chciałbym to zrobić przez sockety, np. tak:

     int sockfd, newsockfd, portno, clilen, n;
     char buffer[256];
     struct sockaddr_in serv_addr, cli_addr;
         
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = [numer_portu]
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_port = htons(portno);
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     
     if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) error("ERROR on binding");
     
     listen(sockfd,5);
     clilen = sizeof(cli_addr);
     newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
     bzero(buffer,256);
     n = read(newsockfd,buffer,255);
     //............. itd.

Ale oczywiście program po wpleceniu tego kodu będzie czekał na połączenie z klientem. Jak powinienem to zrobić, aby daemon mógł odpowiedzieć w każdej chwili, wykonując swoje zaplanowane zadania, a także jak 'śpi'?

z góry dzięki
pozdrawiam
herszt

0

W demonie odpal dwa wątki. Jeden wątek zajmuje się robieniem tych operacji i spaniem, drugi wątek zajmuje się oczekiwaniem na odpytywanie. Ten drugi wątek po prostu używa select() na sockecie na którym oczekujesz zapytań. select() powoduje ze wątek będzie spał aż do chwili gdy nie nadejdzie połączenie.

0

Można też przestawić socketa w tryb nieblokujący:

unsigned long long ulMode=1;
ioctlsocket(socket,FIONBIO,(unsigned long*)&ulMode);

kod z windowsa ale pod linuxem chyba jest podobnie

0

@up ale to się sprowadzi wtedy do pisania własnego select(), a to trochę bez sensu pisać coś co już jest napisane ;)

0

Dzięki za dobre rady!

Jeszcze tylko jedno odnośnie wątków - czy można w obu tych wątkach umieścić nieskończoną pętlę? Czy muszą być spełnione jakieś konkretne warunki?

z góry dzięki
pozdrawiam
herszt

0

Można. Czemu miałoby nie być takiej możliwości? Pamiętaj oczywiście o używaniu mutexów do synchronizacji zapisywania wyników operacji, ale pewnie o tym wiesz.

0

Pamiętam o mutexach, ale się zastanawiam, czy w tym przypadku jest to konieczne - tylko jeden wątek będzie zmianiał wartość zmiennych, natomiast drugi będzie jedynie je czytał. Czy mutexy coś w tym wypadku zmienią?

z góry dzięki
pozdrawiam
herszt

0

Tak, bo zauważ że w chwili aktualizacji danych może być tak:

  • wątek który te dane zbiera / wykonuje operacje zapisał część danych (tzn jest w polowie operacji) ale zostaje uśpiony i przełączony na drugi wątek
  • drugi wątek odczytuje informacje, ale są tam jakieś cuda, bo pierwszy wątek nie zdążył zapisać wszystkich danych
    Dlatego w chwili kiedy zapisujesz musisz mieć wyłączność na te zasoby.
0

Faktycznie! Dzięki ponownie za cenną uwagę! :)

Napisałem cały kod, wszystko działa ok, ale pojawia się mały problem - otóż mój proces widziany jest jako 'defunct' co jak się domyślam jest to proces zombie. Domyślam się, że może go powodować wątek odpowiedzialny za komunikację poprzez sockety:

    void *Server()
    {
     
     /*to samo co w pierwszym poście*/
     
     listen(sockfd,5);
     clilen = sizeof(cli_addr);
     
     while(1) {
	newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
     
	//if (newsockfd < 0) error("ERROR on accept");
     
	bzero(buffer,256);
	n = read(newsockfd,buffer,255);
     
	//if (n < 0) error("ERROR reading from socket");
	//printf("Wiadomosc: %s\n",buffer);
	
	snprintf(dane, 19, "%lu\n\r",dane_wspolne);
	n = write(newsockfd,dane,19);
     
	//if (n < 0) error("ERROR writing to socket");
     }
     pthread_exit((void*) 0);
    }

Czy może powinienem gdzie indziej szukać przyczyny?

z góry dzięki
pozdrawiam
herszt

0

Czy to może mieć jakiś związek z sygnałem SIGCHLD? Choć nie wiem, w którym miejscu taki sygnał mógłby być wysyłany skoro oba wątki chodzą w nieskończonej pętli.

z góry dzięki
pozdrawiam
herszt

0

To co pokazałes nie ma chyba nic wspólnego z tym że proces zostaje zombie. Pokaż raczej jak wygląda uruchamianie tego wszystkiego. Korzystasz tam z fork() albo exec() gdzieś na przykład?

0

Tak. Mam fork(). W założeniu program miał być daemonem więc nieco sobie o tym zasięgnąłem wiedzy i napisałem na podstawie tego co udało mi się dowiedzieć taki kod (oczywiście jest to fragment całego programu):

void signal_handler(int sig) {
    switch(sig) {
        case SIGHUP:
            syslog(LOG_WARNING, "Received SIGHUP signal.");
            break;
        case SIGTERM:
            syslog(LOG_WARNING, "Received SIGTERM signal.");
            break;
        default:
            syslog(LOG_WARNING, "Unhandled signal (%d) %s", strsignal(sig));
            break;
    }
}
 

/***********************************************
 *             tu sa zmienne                   *
 ***********************************************/
     
    void *Pomiar()
    {
      //watek pomiarowy
    }

    void *Server()
    {
      //watek serwera udostepniajacego pomiar
    }

int main(int argc, char *argv[]) {
 
#if defined(DEBUG)
    int daemonize = 0;
#else
    int daemonize = 1;
#endif

openlog("demon",LOG_PID,LOG_DAEMON);
 
    signal(SIGHUP, signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGINT, signal_handler);
    signal(SIGQUIT, signal_handler);
 
    int c;
    while( (c = getopt(argc, argv, "nh|help")) != -1) {
        switch(c){
            case 'h':
                PrintUsage(argc, argv);
                exit(0);
                break;
            case 'n':
                daemonize = 0;
                break;
            default:
                PrintUsage(argc, argv);
                exit(0);
                break;
        }
    }
    printf("%s daemon starting up\n", DAEMON_NAME);
 
#if defined(DEBUG)
    setlogmask(LOG_UPTO(LOG_DEBUG));
    openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
#else
    setlogmask(LOG_UPTO(LOG_INFO));
    openlog(DAEMON_NAME, LOG_CONS, LOG_USER);
#endif
 
    pid_t pid, sid;
 
    if (daemonize) {
	printf("starting the daemonizing process\n");
 
        /* Fork off the parent process */
        pid = fork();
        if (pid < 0) {
            exit(EXIT_FAILURE);
        }
        /* If we got a good PID, then we can exit the parent process. */
        if (pid > 0) {
            exit(EXIT_SUCCESS);
        }
 
        /* Change the file mode mask */
        umask(0);
 
        /* Create a new SID for the child process */
        sid = setsid();
        if (sid < 0) {
            /* Log the failure */
            exit(EXIT_FAILURE);
        }
 
        /* Change the current working directory */
        if ((chdir("/")) < 0) {
            /* Log the failure */
            exit(EXIT_FAILURE);
        }
 
        /* Close out the standard file descriptors */
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
    }
    
    pthread_t pom;
    pthread_t serv;
    int rc1, rc2;
    
    pthread_mutex_init(&impmutex, NULL);
       
    rc1 = pthread_create(&pom, NULL, Pomiar, NULL);
    if(rc1) syslog(LOG_INFO, "nie utworzylem watku pomiarowego!"); else syslog(LOG_INFO, "watek pomiarowy zostal utworzony!");
    
    rc2 = pthread_create(&serv, NULL, Server, NULL);
    if(rc2) syslog(LOG_INFO, "nie utworzylem watku servera!"); else syslog(LOG_INFO, "watek servera zostal utworzony!");
    
    pthread_mutex_destroy(&impmutex);
    pthread_exit(NULL);
    syslog(LOG_INFO, "%s daemon exiting", DAEMON_NAME);
    closelog();
 
    exit(0);
}

z góry dzięki
pozdrawiam
herszt

0

eee

rc1 = pthread_create(&pom, NULL, Pomiar, NULL); //uruchamiasz jeden watek
rc2 = pthread_create(&serv, NULL, Server, NULL); //uruchamiasz drugi watek
pthread_mutex_destroy(&impmutex); //usuwasz semafora mimo ze watki z niego korzystaja o_O
pthread_exit(NULL); //zabijasz watek glowny?!
exit(0); //zabijasz cały proces ?!

Nie ma się co dziwić że się dzieją cuda bo zabijasz watek glowny. Nie jestem pewien, trzeba poszukać w dokumentacji, czy to spowoduje ubicie całego procesu, ale wstawianie instrukcji po pthread_exit() jest chyba bez sensu, bo nie dojdziesz do tego miejsca...
Proponuje wątku głównym zrobić pętlę nieskończoną albo chociaż pthread_join() w oczekiwaniu na zakończenie wątków ktore utworzyłes.

0

Miałem nieskończoną pętlę, ale ją usunąłem... zupełnie nie wiem dlaczego :-) Faktycznie to dość nielogiczne co napisałem. Dzięki za pomoc!

pozdrawiam
herszt

1 użytkowników online, w tym zalogowanych: 0, gości: 1