2010-04-19 6 views
7

J'ai un problème étrange avec un serveur acceptant les connexions TCP. Même s'il y a normalement des processus en attente, à un certain volume de connexions il se bloque.Pourquoi mon script de serveur Perl TCP se bloque-t-il avec de nombreuses connexions TCP?

Version longue:

Le serveur est écrit en Perl et se lie à une prise $srv avec le drapeau de la réutilisation et écouter == 5. Ensuite, il forke en 10 processus avec une boucle de $clt=$srv->accept(); do_processing($clt); $clt->shutdown(2);

Le client écrit en C est aussi très simple - il envoie des lignes, puis reçoit toutes les lignes disponibles et fait shutdown(sockfd, 2); Il n'y a rien d'asynchrone qui se passe et à la fin les files d'attente d'envoi et de réception sont vides (comme indiqué par netstat).

Les connexions ne durent que ~ 20ms. Tous les clients se comportent de la même manière, ont la même implémentation, etc. Supposons maintenant que j'accepte les connexions X du client 1 et une autre X du client 2. Les processus indiquent toujours qu'ils sont inactifs tout le temps. Si j'ajoute un autre X connexions du client 3, soudainement les processus de serveur commencent à se suspendre juste après avoir accepté. Le premier blocage qu'ils font après accept(); est while (<$clt>) ... - mais ils n'obtiennent aucune donnée (dès le premier essai). Soudain, tous les 10 processus sont dans cet état et n'arrêtent pas d'attendre. Sur strace, les processus serveur semblent se bloquer sur read(), ce qui est logique.

Il y a des charges de connexions dans l'état TIME_WAIT appartenant à ce serveur (~ 100 lorsque le problème commence à se manifester), mais cela pourrait être un faux-fuyant.

Que pourrait-il se passer ici? Après un peu plus d'analyse: Il s'est avéré que le client était fautif, ne fermant pas correctement les connexions précédentes avant d'essayer le suivant. Les serveurs au début de la liste d'équilibrage de charge étaient des connexions périmées.

+1

Avez-vous désactivé la mise en mémoire tampon sur toutes vos sockets? Vous devrez peut-être poster d'autres exemples de code. –

+0

Vous ne savez pas ce que je peux vous donner ici en code - c'est vraiment simple. Le serveur fonctionne sur des lignes, donc les lectures sont mises en mémoire tampon et traitées avec '<...>' - sauf si vous voulez dire quelque chose d'autre ici? Le code client C fait un standard 'connect (...);' et write (sockfd, request, ...); '- j'essaierai de désactiver la mise en mémoire tampon ici et de rendre compte. – viraptor

+0

@Eric Strom: Je suis confus maintenant - que vouliez-vous dire en désactivant la mise en mémoire tampon? J'utilise un simple 'write (...)' côté client - il y a bien sûr du nagle, mais cela garantit le transfert dans les 0.2s suivants (plus ou moins). Alors, quel genre de tampon aviez-vous en tête? – viraptor

Répondre

0

Est-ce que ça fait un bond puis une longue pause (environ deux minutes environ), puis une nouvelle poussée? Si c'est le cas, vous ne pouvez pas avoir votre système de fichiers max limité limite assez élevé.

+0

Les fichiers ouverts ulimit sont à 1024. Le serveur n'excède jamais plus de 100 connexions mortes (time_wait) et jamais plus de 10 connexions en direct (1 par processus forké). Lorsque les connexions bloquées commencent, elles se produisent autour d'un quart des connexions (3 passeront, l'une bloquera pendant environ 5 secondes, jusqu'à ce que la protection de temporisation entre en action et réponde le processus). – viraptor

1

Ce n'est probablement pas la solution à votre problème, mais cela pourrait résoudre un problème que vous rencontrerez dans le futur: n'oubliez pas de fermer() les prises lorsque vous avez terminé! shutdown() déconnectera le flux, mais il utilisera toujours un descripteur de fichier. Comme vous avez dit que strace montre des processus bloqués dans read(), votre problème semble être que le client n'envoie pas les données que vous attendez qu'il envoie. Vous devez soit corriger votre client, soit ajouter une alarme() à vos processus serveur afin qu'ils puissent survivre aux clients morts.

Questions connexes