2016-03-15 3 views
3

J'ai un serveur écrit en C qui est bloqué à la fonction accept() et attend de nouvelles connexions entrantes. Lorsqu'une nouvelle connexion est acceptée, elle crée un nouveau processus en appelant le fork(). Je n'utilise pas epoll car chaque socket client est géré par un processus indépendant, et l'une des bibliothèques qu'il utilise se bloque dans un environnement multi-thread.Programmation de socket: accept() retardé

Voici le code du serveur:

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

Le client est écrit en Java, il se connecte au serveur en utilisant la bibliothèque junixsocket depuis Java ne supporte pas les socket de domaine Unix. Lorsqu'il est connecté au serveur, il envoie une requête (en-tête + document XML) et attend la réponse du serveur.

Voici le code du client:

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(); 

Maintenant, le problème est quand j'ai 3 fils de clients qui se connectent au serveur en même temps. J'ai toujours 1 tâche en cours tandis que les 2 autres attendent que le premier soit fini.

J'ai vérifié les journaux. Tous les 3 threads client se sont connectés et ont envoyé une requête au serveur (presque) en même temps, mais le serveur a seulement accepté le premier arrivé, et a retardé les 2 autres. Selon les journaux, il y a un délai de 3 minutes entre connect côté client et accept côté serveur. Au début, je pensais que le retard pouvait être causé par une sorte de tampon, donc j'appelle OutputStream.flush() après chaque appel OutputStream.write, mais le problème persiste.

Je ne peux pas comprendre ce qui pourrait causer ce retard, une idée s'il vous plaît?

Merci.

15 Mar Mise à jour 2016

pstack montre que le processus parent a été bloqué à waitpid dans mon gestionnaire SIGCHLD. C'était probablement pourquoi le accept ne revenait pas quand une nouvelle connexion entrante arrivait car la procédure d'exécution était interrompue par le gestionnaire de signal.

Voici le code de mon gestionnaire de signal:

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

Et où est le code du côté serveur C? Ce serait le premier suspect pour ce genre de problème. Il est assez difficile de résoudre ce problème sans aucun code. –

+0

Désolé @ AnttiHaapala, j'ai ajouté le code du serveur. – vesontio

+0

Refusée. Jusqu'à présent, je ne vois rien de mal avec le code du serveur :(Comment est la sortie du journal, est-il un délai de 3 minutes entre «En attente de la nouvelle connexion entrante» et «Connexion acceptée»? Peut-être du côté client alors –

Répondre

1

Votre waitpid() état est mauvais, vous voulez seulement continuer à appeler waitpid() si elle a recueilli un processus enfant, vous devez faire

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