5 votes

Écriture sur un socket TCP fermé par le pair

J'ai une application client-serveur où chaque partie communique avec l'autre via un socket TCP.

J'établis correctement la connexion, puis je fais planter le serveur AVANT que le client n'écrive des données sur le socket.
Ce que je vois, c'est que le premier write() (côté client) est réussie et renvoie le nombre réel d'octets écrits, tandis que les suivantes renvoient (comme je m'y attendais) -1 (recevant un SIGPIPE ) et errno=EPIPE .

Pourquoi le premier write() réussit même si le socket est déjà fermé ?

EDIT Parfois aussi les éléments suivants write() ont une valeur de retour positive, comme si tout se passait bien.

8voto

Nicholas Wilson Points 4464

Vous êtes confus par ce que la valeur de retour de write() signifie. Ça ne veut pas dire, "le pair a reçu les données et les a reconnues". Cela signifie plutôt "J'ai mis en mémoire tampon tant d'octets à envoyer au pair et ils sont sous ma responsabilité maintenant, donc vous pouvez les oublier (et je n'ai pas d'erreurs en attente)".

C'est-à-dire que si la pile TCP accepte l'écriture et retourne n octets, cela ne signifie pas qu'ils ont déjà été écrits, mais qu'ils sont en attente d'écriture. Il faudra un certain temps, peut-être 30s après le début de l'envoi du trafic réseau, avant que la pile n'abandonne et ne vous renvoie une erreur. Pendant ce temps, vous avez pu faire plusieurs appels à write() qui ont réussi à mettre en file d'attente les données à envoyer. (L'erreur d'écriture sera renvoyée dans environ 30s si le pair a disparu, ou immédiatement si le pair peut être contacté et envoie un paquet RST directement pour indiquer que la connexion est morte).

3voto

jop Points 2130

Cela est lié au fonctionnement de TCP/IP, qui peut être décrit grossièrement comme deux demi-connexions essentiellement indépendantes. Lorsque vous fermez le socket sur le serveur, le client est informé qu'il ne recevra plus de données de la part du serveur. C<-S demi-connexion, réveil read() immédiatement, mais pas sur le C->S direction. Il ne reçoit une réponse qui réinitialise la connexion qu'après avoir essayé d'envoyer des données. Je recommande le Guide TCP/IP pour plus de détails.

La raison pour laquelle parfois vous pouvez write() deux fois, c'est que vous écrivez plus vite que le temps d'aller-retour et que vous pouvez extraire une seconde write() avant la réponse à la première.

0voto

Zeev Points 22

J'utilise la méthode suivante pour détecter une condition de serveur déconnecté :

Après avoir obtenu le timeout select() sur un socket (rien n'a été reçu, alors que c'était censé être le cas), la commande 'system("ping -c 1 -w 1 server");' est activée. Si le serveur est opérationnel et qu'il est juste en retard, la commande ping reviendra en moins de 0,1 seconde. Sinon (le serveur est en panne), la commande ping sera renvoyée en 1 seconde.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X