套接字编程:accept()延迟

时间:2016-03-15 06:23:51

标签: java c sockets unix-socket multiprocess

我有一个用C编写的服务器,它在函数accept()被阻塞并等待新的传入连接。接受新连接后,它会通过调用fork()来创建新进程。我不使用epoll,因为每个客户端套接字都由一个独立的进程处理,并且它使用的一个库在多线程环境中崩溃。

以下是服务器的代码:

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个一直在等待,直到第一个完成。

我检查了日志。所有3个客户端线程都已经(几乎)同时连接并向服务器发送了请求,但是服务器只接受了第一个到达,并延迟了另外两个。根据日志,客户端connect与服务器端accept之间的延迟时间为3分钟。

起初我认为延迟可能是由某种缓冲引起的,所以我会在每次OutputStream.flush()通话后拨打OutputStream.write,但问题仍然存在。

我无法弄清楚可能导致这种延迟的原因,有什么想法吗?

谢谢。

2016年3月15日更新

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.");
}

1 个答案:

答案 0 :(得分:1)

您的waitpid()条件错误,您只想继续调用waitpid(),如果它收集了子进程,那么您需要这样做

while ((child = waitpid(-1, &status, WNOHANG)) > 0) {
     continue;
 }