Правильный способ обработки SIGCHLD, EINT и accept() в Linux
У меня есть программа, которая создает TCP-сервер. Когда accept() подключается к клиенту, я выполняю fork() и обрабатываю соединение. Когда этот клиент покидает его, он вызывает waitpid() из-за SIGCHLD, но это вызывает EINTR в accept(). Мой вопрос, как это должно быть обработано? Я прочитал так много разных способов.
Большинство говорят, что нужно игнорировать EINT и попробовать снова accept(). Я даже видел макрос для этого: TEMP_FAILURE_RETRY(). Некоторые говорят, чтобы установить флаги sigaction SA_RESTART и SA_NOCLDSTOP. Я пробовал это, и это вводит другие ошибки (errno = ECHILD). Кроме того, как ребенок должен выйти? Я видел как _exit(0), так и exit(0).
int main( int argc, char *argv[] )
{
int sockfd, newsockfd, clilen;
struct sockaddr_in cli_addr;
int pid;
f_SigHandler();
sockfd = f_SetupTCPSocket();
clilen = sizeof(cli_addr);
while (1)
{
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
{
if( errno == EINTR ) continue;
else exit(1) ;
}
pid = fork();
if (pid == 0)
{
close(sockfd);
doprocessing();
close(newsockfd);
_exit(0);
}
else
{
close(newsockfd);
}
}
}
Обработка SIGCHLD:
void f_ChildHandler(int signal_number)
{
while (waitpid(-1, NULL, WNOHANG) > 0)
{
}
}
void f_SigHandler(void)
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = f_ChildHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGCHLD, &sa, NULL);
}
1 ответ
В твоем случае равнина SA_RESTART
и waitpid()
в обработчике наверное хватит. Когда код выхода неинтересен, вы можете передать SA_NOCLDWAIT
дополнительно.
Когда выход клиента должен быть обработан более сложным способом, вы можете поймать EINTR
в основной программе и звоните waitpid()
там. Чтобы сделать его свободным, вы должны использовать pselect()
заблокировать сигнал. Кроме того, вы можете создать signalfd и использовать его в select/poll с вашим sockfd
,
Ребенок должен использовать _exit()
предотвратить выполнение обработчиков atexit() (например, которые записывают записи завершения в файл).