2010-02-10 11 views
5

J'ai une application qui se compose de deux processus (appelons-les A et B), connectés les uns aux autres via des sockets de domaine Unix. La plupart du temps cela fonctionne très bien, mais certains utilisateurs signalent le comportement suivant:Qu'est-ce qui peut provoquer une erreur EPIPE spontanée sans que l'un des deux finisse par appeler close() ou s'écraser?

  1. A envoie une requête à B. Cela fonctionne. A commence à lire la réponse de B.
  2. B envoie une réponse à A. L'appel write() correspondant renvoie une erreur EPIPE, et par conséquent B close() le socket. Cependant, A a fait pas fermer() le socket, et il ne s'est pas écrasé.
  3. L'appel de read() renvoie 0, indiquant la fin du fichier. A pense que B a fermé prématurément la connexion.

Les utilisateurs ont également signalé des variations de ce comportement, par exemple:

  1. A envoie une demande à B. Cela fonctionne en partie, mais avant toute la demande est envoyée appel en écriture() d'un retour EPIPE et en conséquence A close() le socket. Cependant, B n'a pas fermé() le socket, et il ne s'est pas écrasé.
  2. B lit une requête partielle et obtient soudainement un EOF.

Le problème est que je ne peux pas reproduire ce comportement localement. J'ai essayé OS X et Linux. Les utilisateurs sont sur une variété de systèmes, principalement OS X et Linux.

choses que je l'ai déjà essayé et estimais:

  • fermer des bogues Double() (close() est appelée deux fois sur le même descripteur de fichier): probablement pas que cela entraînerait des erreurs de EBADF, mais Je ne les ai pas vus.
  • Augmentation de la limite maximale du descripteur de fichier. Un utilisateur a rapporté que cela a fonctionné pour lui, le reste a rapporté que ce n'était pas le cas.

Quoi d'autre peut éventuellement provoquer un comportement comme celui-ci? Je sais avec certitude que ni A ni B ne ferment prématurément le socket, et je sais avec certitude qu'aucun d'entre eux ne s'est écrasé parce que A et B ont pu signaler l'erreur. C'est comme si le noyau avait soudainement décidé de retirer la fiche de la prise pour une raison quelconque.

Répondre

3

Peut-être que vous pourriez essayer strace comme décrit dans (ou son GUI cousin.): http://modperlbook.org/html/6-9-1-Detecting-Aborted-Connections.html

Je suppose que votre problème est lié à celui décrit ici: http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable

Malheureusement, j'ai un similar problem moi-même, mais je n'ai pas réussi à le réparer avec les conseils donnés. Cependant, peut-être que cette chose SO_LINGER fonctionne pour vous.

+0

Il s'est avéré que le descripteur de fichier du serveur a été ajouté avec l'indicateur EPOLLET à la file d'attente epoll qui semble être fausse. – user206268

+2

Pas exactement la réponse que je cherchais mais la page TCP à laquelle vous vous êtes connecté est très instructive! Il est en baisse maintenant par Archive.org l'a toujours: http://ia700609.us.archive.org/22/items/TheUltimateSo_lingerPageOrWhyIsMyTcpNotReliable/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable .html – Hongli

2
  • shutdown() peut avoir été fait appel à l'une des extrémités de douille .

  • Si chaque côté peut fourche et exécuter un processus enfant , assurez-vous que le FD_CLOEXEC (close-on-exec) est défini sur le descripteur de fichier socket si vous ne l'avez pas l'intention qu'elle soit héritée par le enfant. Sinon, le processus enfant pourrait (accidentellement ou autrement) être en manipulant votre connexion socket.

+0

Merci, mais aucune des situations ne s'applique à mon programme. – Hongli

0

Je voudrais également vérifier qu'il n'y a pas de pare-feu sournois au milieu. Il est possible qu'un noeud de transfert intermédiaire sur l'itinéraire envoie un RST.La meilleure façon de suivre cette baisse est bien sûr the packet sniffer

+0

... sur une socket de domaine UNIX? C'est un protocole local seulement. – ephemient

+0

Oh ... tire, j'ai complètement raté ça. Merci. –