No to teraz program serwera. Kompletny program źródłowy znaleźć można w linku na poprzedniej stronie, pominiemy więc tu te jego fragmenty, które nie wymagają objaśnienia, jak pliki nagłówkowe, definicje zmiennych.
Nasz program, jak każdy przyzwoity serwer powinien nieustannie odbierać od programów klienckich prośby o zrobienie zdjęcia. Sam proces robienia zdjęcia trwa jednak kilka sekund, kamera musi ocenić jakość oświetlenia, wyostrzyć obraz itp.
W tym czasie serwerowi trudno byłoby równocześnie obsługiwać prośby klientów, dlatego w celu zrobienia zdjęcia za każdym razem uruchomimy proces potomny, który się tym zajmie.
Po skończeniu pracy procesu potomnego pozostaje on jednak nadal w systemie jako tak zwany proces zombie. Nie cały, tylko pewne jego elementy, ale zostaje.
Chodzi o to, że proces nadrzędny może chcieć się na przykład dowiedzieć, czy proces potomny nie zakończył się błędnie.
Proces zombie zostanie usunięty po skończeniu pracy procesu, który go uruchomił, jeśli jednak, jak w naszym przypadku, proces nadrzędny pracuje cały czas, musimy sami zadbać o jego usunięcie.Po skończeniu procesu potomnego do procesu nadrzędnego wysyłany jest sygnał SIGCHLD, obsługujemy go, co powoduje usunięcie procesu zombie.
Zapamietanie statusu zakończenia procesu w zmiennej globalnej nie jest w tym programie potrzebne, można go użyć na przykład do obsługi przypadków, że zdjęcie się nie zrobilo.
A więc procedura obsługi przerwania:
sig_atomic_t child_exit_status; void clean_up_child_process(int signal_num) { /* remove child process */ wait (&status); /* save exit status in a global variable */ child_exit_status = status; }
I już w procedurze main jej użycie:
main (argc, argv) int argc; char *argv[]; { /* handle SIGCHLD by calling clean_up_child_process */ struct sigaction sigchild_action; memset(&sigchild_action, 0, sizeof(sigchild_action)); sigchild_action.sa_handler = &clean_up_child_process; sigaction(SIGCHLD, &sigchild_action, NULL);