En C, j'ai compris que si nous fermons un socket, cela signifie que le socket sera détruit et pourra être réutilisé plus tard.
Et la fermeture? La description indique qu'elle ferme la moitié d'une connexion duplex à cette prise. Mais ce socket sera-t-il détruit comme close
un appel système?
c
sockets
networking
tshepang
la source
la source
Réponses:
Ceci est expliqué dans le guide de mise en réseau de Beej.
shutdown
est un moyen flexible de bloquer la communication dans une ou les deux directions. Lorsque le deuxième paramètre estSHUT_RDWR
, il bloquera à la fois l'envoi et la réception (commeclose
). Cependant,close
c'est le moyen de détruire réellement une socket.Avec
shutdown
, vous pourrez toujours recevoir les données en attente que le pair a déjà envoyées (merci à Joey Adams de l'avoir noté).la source
shutdown
deux directions, mais pasclose
si vous avez faitFILE
référence au socket à l'aidefdopen
. Si vousclose
utilisez le socket, un nouveau fichier ouvert pourrait se voir attribuer le même fd, et l'utilisation ultérieure deFILE
lira / écrira au mauvais endroit, ce qui pourrait être très mauvais. Si vous venezshutdown
, l'utilisation subséquente de laFILE
donnera juste des erreurs jusqu'à ce quefclose
soit appelé.shutdown
: pour signaler EOF au pair et toujours pouvoir recevoir les données en attente envoyées par le pair.Aucune des réponses existantes ne dit aux gens comment
shutdown
etclose
fonctionne au niveau du protocole TCP, il vaut donc la peine d'ajouter cela.Une connexion TCP standard est interrompue par une finalisation à 4 voies:
Cependant, il existe une autre façon "émergente" de fermer une connexion TCP:
Dans mon test avec Wireshark, avec les options de socket par défaut,
shutdown
envoie un paquet FIN à l'autre extrémité, mais c'est tout ce qu'il fait. Jusqu'à ce que l'autre partie vous envoie le paquet FIN, vous pouvez toujours recevoir des données. Une fois que cela s'est produit, vousReceive
obtiendrez un résultat de taille 0. Donc, si vous êtes le premier à arrêter l'envoi, vous devez fermer le socket une fois que vous avez fini de recevoir les données.D'un autre côté, si vous appelez
close
alors que la connexion est toujours active (l'autre côté est toujours actif et vous pouvez également avoir des données non envoyées dans la mémoire tampon du système), un paquet RST sera envoyé à l'autre côté. C'est bon pour les erreurs. Par exemple, si vous pensez que l'autre partie a fourni des données erronées ou a refusé de fournir des données (attaque DOS?), Vous pouvez fermer le socket immédiatement.Mon opinion sur les règles serait:
shutdown
avantclose
si possibleImplémentations idéales pour SHUT_RD et SHUT_WR
Les éléments suivants n'ont pas été testés, faites confiance à vos risques et périls. Cependant, je pense que c'est une façon raisonnable et pratique de faire les choses.
Si la pile TCP reçoit un arrêt avec SHUT_RD uniquement, elle doit marquer cette connexion comme plus de données attendues. Toutes les
read
demandes en attente et suivantes (quel que soit le thread dans lequel elles se trouvent) seront alors renvoyées avec un résultat de taille nulle. Cependant, la connexion est toujours active et utilisable - vous pouvez toujours recevoir des données OOB, par exemple. En outre, le système d'exploitation supprimera toutes les données qu'il reçoit pour cette connexion. Mais c'est tout, aucun colis ne sera envoyé de l'autre côté.Si la pile TCP reçoit un arrêt avec SHUT_WR uniquement, elle doit marquer cette connexion car plus aucune donnée ne peut être envoyée. Toutes les demandes d'écriture en attente seront terminées, mais les demandes d'écriture suivantes échoueront. De plus, un paquet FIN sera envoyé à un autre côté pour les informer que nous n'avons plus de données à envoyer.
la source
shutdown()
la connexion et puis il n'est plus en vie. Vous avez toujours le descripteur de fichier. Vous pouvez toujours àrecv()
partir du tampon de réception. Et vous devez toujours appelerclose()
pour supprimer le descripteur de fichier.Il existe certaines limitations
close()
qui peuvent être évitées si l'on utilise à lashutdown()
place.close()
mettra fin aux deux directions sur une connexion TCP. Parfois, vous voulez dire à l'autre point de terminaison que vous avez fini d'envoyer des données, mais que vous souhaitez quand même recevoir des données.close()
décrémente le nombre de références des descripteurs (conservé dans l'entrée de la table de fichiers et compte le nombre de descripteurs actuellement ouverts qui font référence à un fichier / socket) et ne ferme pas le socket / fichier si le descripteur n'est pas 0. Cela signifie que si vous bifurquez, le nettoyage ne se produit qu'après que le nombre de références est tombé à 0. Avec l'shutdown()
un, on peut lancer une séquence de fermeture TCP normale en ignorant le nombre de références.Les paramètres sont les suivants:
int how
peut être:SHUT_RD
ou les0
autres réceptions sont interditesSHUT_WR
ou d'1
autres envois sont interditsSHUT_RDWR
ou2
encore les envois et les réceptions sont interditsla source
Cela peut être spécifique à la plate-forme, j'en doute quelque peu, mais de toute façon, la meilleure explication que j'ai vue est ici sur cette page msdn où ils expliquent l'arrêt, les options de persistance , la fermeture de socket et les séquences générales de terminaison de connexion.
En résumé, utilisez shutdown pour envoyer une séquence d'arrêt au niveau TCP et close pour libérer les ressources utilisées par les structures de données de socket dans votre processus. Si vous n'avez pas émis de séquence d'arrêt explicite au moment où vous appelez close, une est lancée pour vous.
la source
J'ai également réussi sous Linux à utiliser
shutdown()
un pthread pour forcer un autre pthread actuellement bloquéconnect()
à abandonner tôt.Sous d'autres OS (OSX au moins), j'ai trouvé l'appel
close()
étaient suffisants pourconnect()
échouer.la source
"shutdown () ne ferme pas réellement le descripteur de fichier, il modifie simplement son utilisation. Pour libérer un descripteur de socket, vous devez utiliser close ()." 1
la source
Fermer
Lorsque vous avez fini d'utiliser un socket, vous pouvez simplement fermer son descripteur de fichier avec close; S'il reste des données en attente de transmission via la connexion, normalement close tente de terminer cette transmission. Vous pouvez contrôler ce comportement à l'aide de l'option de socket SO_LINGER pour spécifier un délai d'expiration; voir Options de socket.
Fermer
Vous pouvez également arrêter uniquement la réception ou la transmission sur une connexion en appelant shutdown.
La fonction d'arrêt coupe la connexion de la prise. Son argument comment spécifie l'action à effectuer: 0 Arrêtez de recevoir des données pour ce socket. Si d'autres données arrivent, rejetez-les. 1 Arrêtez d'essayer de transmettre des données depuis cette prise. Jetez toutes les données en attente d'envoi. Arrêtez de chercher l'accusé de réception des données déjà envoyées; ne le retransmettez pas s'il est perdu. 2 Arrêtez la réception et la transmission.
La valeur de retour est 0 en cas de succès et -1 en cas d'échec.
la source
dans mon test.
close
enverra le paquet fin et détruira fd immédiatement lorsque le socket n'est pas partagé avec d'autres processusshutdown
SHUT_RD , le processus peut toujours récupérer les données du socket, maisrecv
renverra 0 si le tampon TCP est viderecv
.shutdown
SHUT_WR enverra un paquet fin pour indiquer que les autres envois sont interdits. le pair peut récupérer des données mais il récupérera 0 si son tampon TCP est videshutdown
SHUT_RDWR (égal à utiliser à la fois SHUT_RD et SHUT_WR ) enverra le premier paquet si le pair envoie plus de données.la source
close()
envoyé RST sur Linux au lieu de FIN.recv()
seront renvoyées» n'est pas correct. 2. Le comportement si l'homologue envoie plus de données aprèsSHUT_RD
dépend de la plate-forme.