Java 套接字编程:accept()延迟

Java 套接字编程:accept()延迟,java,c,sockets,unix-socket,multiprocess,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("Awaiti

我有一个用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);
    }
}
现在的问题是,当我有3个客户端线程同时连接到服务器时。我总是有一个任务在运行,而另外两个一直等到第一个任务完成

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

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

我想不出是什么原因造成了这次延误,你知道吗

多谢各位

2016年3月15日更新

pstack
显示父进程在我的
SIGCHLD
处理程序中的
waitpid
被阻止。这就是为什么当新的传入连接到达时,
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.");
}
static void\u zombie\u reaper(int signum){
智力状态;
pid_t儿童;
if(signum!=SIGCHLD){
返回;
}
while((child=waitpid(-1,&status,WNOHANG))!=-1){
继续;
}
}
/*主要功能*/
结构信号动作信号动作;
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(“未能注册信号处理程序”);
}
您的
waitpid()
条件错误,您只想在waitpid()收集子进程时继续调用它,因此需要执行以下操作

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

C服务器端的代码在哪里?这将是这类问题的第一个嫌疑犯。没有任何代码就很难解决这个问题。抱歉@AnttiHaapala,我添加了服务器代码。@user3386109通常问题是将
fork()
ing与线程混合在一起;如果您使用其他人的框架,您可能会在不知道的情况下拥有线程it@user3386109也许是对的。是否在子进程中关闭“srv_sock”套接字?是否有使用
fork
的原因?如果您关心性能,那么当您扩展到10000个连接(以及10000个线程/进程/任何东西)时,为每个套接字启动单独的线程(更不用说进程)会让您大失所望。考虑使用非阻塞或异步套接字调用,或者将套接字选项设置为非阻塞(这与使用非阻塞或异步套接字调用不同)。您应该能够通过一个线程实现性能合理的服务器应用程序。如果这不能很好地执行,您可以使用
pthread\u create
,而不是
fork
,很好地扩展它。
while ((child = waitpid(-1, &status, WNOHANG)) > 0) {
     continue;
 }