2016-03-15 4 views
3

У меня есть сервер, написанный на C, который заблокирован функцией accept() и ждет новых входящих соединений. Когда новое соединение принято, он создает новый процесс, вызывая fork(). Я не использую epoll, так как каждый клиентский сокет обрабатывается независимым процессом, а одна из библиотек, в которой он использует аварийные ситуации в многопоточной среде.Программирование на сокет: accept() delayed

Вот код сервера:

srv_sock = init_unix_socket(); 
listen(srv_sock, 5); 
/* Other code which handles SIGCLD. */ 
while (1) { 
    log_info("Awaiting new incoming connection."); 
    clt_sock = accept(srv_sock, NULL, NULL); 
    if (clt_sock < 0) { 
     log_err("Error ..."); 
     continue; 
    } 
    log_info("Connection %d accepted.", clt_sock); 

    cld_pid = fork(); 
    if (cld_pid < 0) { 
     log_err("Failed to create new process."); 
     close(clt_sock); 
     continue; 
    } 
    if (clt_pid == 0) { 
     /* Initialize libraries. */ 
     /* Handle client connection ... */ 
     shutdown(clt_sock, SHUT_RDWR); 
     close(clt_sock); 
     _exit(0); 
    } 
    else { 
     log_info("Child process created for socket %d.", clt_sock); 
     close(clt_sock); 
    } 
} 

Клиент написан на Java, он подключается к серверу с использованием библиотеки junixsocket, поскольку Java не поддерживает сокет домена Unix. Когда он подключен к серверу, он отправляет запрос (заголовок + XML-документ) и ждет ответа от сервера.

Вот код клиента:

File socketFile = new File(UNIX_SOCKET_PATH); 
AFUNIXSocket socket = AFUNIXSocket.newInstance(); 
socket.connect(new AFUNIXSocketAddress(socketFile)); 

InputStream sis = socket.getInputStream(); 
OutputStream sos = socket.getOutputStream(); 
logger.info("Connected with server."); 

byte[] requestHeader; 
byte[] requestBuffer; 

sos.write(requestHeader, 0, requestHeader.length); 
logger.info("Header sent."); 

sos.write(requestBuffer, 0, requestBuffer.length); 
logger.info("Request XML sent."); 

sos.flush(); 

Теперь проблема, когда у меня есть 3 клиентских потоков, которые подключаются к серверу одновременно. У меня всегда есть 1 задача, в то время как остальные 2 продолжают ждать, пока первый не будет завершен.

Я проверил журналы. Все три клиентские потоки подключили и отправили запрос на сервер (почти) в одно и то же время, но сервер только принял первый, и отложил 2 других. Согласно журналам, на стороне клиента существует задержка 3 минуты между connect и accept на стороне сервера.

Сначала я думал, что задержка может быть вызвана каким-то буфером, поэтому я вызываю OutputStream.flush() после каждого звонка OutputStream.write, но проблема не устранена.

Не могу понять, что может вызвать эту задержку, любая идея, пожалуйста?

спасибо.

Update Mar 15 2016

pstack показывает, что родительский процесс был заблокирован в waitpid в моем SIGCHLD обработчика. Вероятно, причина, по которой accept не возвращалась, когда прибыло новое входящее соединение, когда процедура выполнения была прервана обработчиком сигнала.

Вот код моего обработчика сигнала:

static void _zombie_reaper (int signum) { 
    int status; 
    pid_t child; 

    if (signum != SIGCHLD) { 
     return; 
    } 
    while ((child = waitpid(-1, &status, WNOHANG)) != -1) { 
     continue; 
    } 
} 

/* In main function */ 
struct sigaction sig_act; 
memset(&sig_act, 0, sizeof(struct sigaction)); 
sigemptyset(&sig_act.sa_mask); 
sig_act.sa_flags = SA_NOCLDSTOP; 
sig_act.sa_handler = _zombie_reaper; 
if (sigaction(SIGCHLD, &sig_act, NULL) < 0) { 
    log_err("Failed to register signal handler."); 
} 
+0

А где код сервера C? Это было бы первым подозреваемым в подобных проблемах. Трудно решить эту проблему без какого-либо кода. –

+0

Извините @AttttiHaapala, я добавил код сервера. – vesontio

+0

Upvoted. До сих пор я не вижу ничего плохого в коде сервера :(Как вывод журнала, есть ли задержка в 3 минуты между «Ожидание нового входящего соединения» и «Соединение принято»? Возможно, это на стороне клиента, тогда –

ответ

1

Ваше waitpid() состояние является неправильным, вы только хотите продолжить вызова waitpid(), если она собрана дочерний процесс, так что вам нужно сделать

while ((child = waitpid(-1, &status, WNOHANG)) > 0) { 
    continue; 
} 
Смежные вопросы