У меня есть сервер, написанный на 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.");
}
А где код сервера C? Это было бы первым подозреваемым в подобных проблемах. Трудно решить эту проблему без какого-либо кода. –
Извините @AttttiHaapala, я добавил код сервера. – vesontio
Upvoted. До сих пор я не вижу ничего плохого в коде сервера :(Как вывод журнала, есть ли задержка в 3 минуты между «Ожидание нового входящего соединения» и «Соединение принято»? Возможно, это на стороне клиента, тогда –