2016-03-15 62 views
3

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

这里是服务器的代码:

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

C服务器端的代码在哪里?这将是这类问题的第一个嫌疑犯。没有任何代码就很难解决这个问题。 –

+0

对不起@AnttiHaapala,我已经添加了服务器代码。 – vesontio

+0

Upvoted。到目前为止,我看不出任何错误的服务器代码:(如何日志输出,是否有'等待新的传入连接.'和'接受连接'之间3分钟的延迟?也许它是在客户端然后 –

回答

1

waitpid()条件是错误的,你只需要继续调用waitpid函数(),如果它收集的一个子进程,所以你需要做的

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