36 votes

Comment puis-je vérifier si un socket (TCP) est (dé)connecté en C# ?

Comment vérifier un socket (TCP) pour savoir s'il est connecté ?

J'ai lu à propos de la Socket.Connected la propriété dans MSDN mais il est dit qu'il ne montre que l'état en fonction de la dernière entrée/sortie. Ce n'est pas utile pour moi, car je veux faire ceci avant en essayant de lire à partir de la prise. La section des remarques note également que :

Si vous avez besoin de déterminer l'état actuel de la connexion, effectuez un appel appel Send non bloquant, à zéro octet. Si l'appel revient avec succès ou lance un code d'erreur WAEWOULDBLOCK (10035), la socket est toujours connectée. connectée ; sinon, la socket n'est plus plus connectée.

L'exemple de la même page montre comment procéder. (1) Mais un message de Ian Griffiths dit que je devrais lire de la prise, et non envoyer à travers elle.

Un autre message de Pete Duniho dit :

... après que vous ayez appelé Shutdown() , appelez Receive() jusqu'à ce qu'il renvoie 0 (en supposant que le terminal distant ne va pas ne va pas réellement vous envoyer quelque chose, cela se produira dès que le point de terminaison a reçu toutes vos données). données). Si vous ne faites pas cela, vous n'avez aucune assurance que le point de terminaison distant a effectivement reçu toutes les données que vous avez envoyées, même en utilisant une douille.

Je ne comprends pas vraiment sa déclaration sur le fait d'appeler Receive() pour s'assurer que le point d'accès distant a bien reçu toutes les données que je envoyé . (Les sockets bloquent-ils la réception jusqu'à ce que le tampon d'envoi soit vide ?)

Je suis confus par les différentes méthodes proposées. Pourriez-vous les expliquer ?


(1) Je me demande pourquoi le exemple pour le Socket.Connected alloue un tableau de 1 octet, bien qu'elle appelle Send avec une longueur de 0 ?

22voto

Quassnoi Points 191041

La mort d'une socket change son comportement de plusieurs façons, donc ces méthodes sont toutes deux valables :)

Avec les deux méthodes, vous vérifiez réellement les parties du comportement de la socket qui changent après la déconnexion.

Je ne comprends pas vraiment sa déclaration concernant l'appel de Receive() pour s'assurer que le point de terminaison distant a bien reçu toutes les données que j'ai envoyées. (Les sockets bloquent-ils la réception jusqu'à ce que le tampon d'envoi soit vide ?)

TCP est un protocole fiable, ce qui signifie que chaque paquet que vous envoyez doit faire l'objet d'un accusé de réception. L'accusé de réception implique l'envoi des paquets avec ACK activé. Ces paquets peuvent ou non contenir des données supplémentaires (charge utile).

Lorsque la prise est connectée, Receive() bloquera jusqu'à ce que la socket reçoive un paquet avec une charge utile non vide. Mais quand la socket est déconnectée, Receive() reviendra dès que le dernier ACK paquet arrive.

Appel à Receive() s'assure que vous recevoir qui durent ACK de votre terminal distant ou un délai de déconnexion se produit et vous serez en mesure de recevoir rien de plus sur cette prise.

L'exemple de la même page montre comment procéder. (Je me demande pourquoi il alloue un tableau de 1 octet, même s'il appelle Send avec une longueur de 0). Mais un post de Ian Griffiths dit que je devrais lire depuis la socket, et non pas envoyer à travers elle.

Lorsque send() En accédant à une socket, vous essayez en fait d'ajouter des données à la fin de la file d'attente de la socket. S'il reste de la place dans la mémoire tampon, alors votre Send() retourne instantanément, sinon, le Send() des blocs jusqu'à ce qu'il y ait un endroit.

Lorsque la prise est en état de déconnexion, TCP/IP La pile empêche toute autre opération avec le tampon, c'est pourquoi Send() renvoie une erreur.

Send() met en œuvre une vérification de base des pointeurs, ce qui signifie qu'il échoue lorsqu'un fichier NULL lui est passé. Vous pouvez probablement passer n'importe quelle constante non nulle comme pointeur, mais vous feriez mieux d'allouer 1 octet au lieu d'inventer la constante - juste au cas où.


Vous pouvez utiliser la méthode de votre choix, car aucune d'entre elles n'est gourmande en ressources. Tant qu'elles sont utilisées pour vérifier la connexion des sockets, elles sont identiques.

Quant à moi, je préférerais Receive() car c'est ce que l'on fait normalement dans un cycle et que l'on attend. Vous obtenez une valeur non nulle de Receive() vous traitez les données, vous obtenez un zéro, vous traitez la déconnexion.

6voto

loaf of bread Points 41

" Si vous devez déterminer l'état actuel de la connexion, effectuez un appel Send non bloquant, à zéro octet. Si l'appel retourne avec succès ou lance un code d'erreur WAEWOULDBLOCK (10035), alors la socket est toujours connectée ; sinon, la socket n'est plus connectée." -- malheureusement, cela ne fonctionne même pas !

mySocket.Blocking = false;
byte[] buffer = new byte[1];
int iSent = mySocket.Send(buffer, 0, SocketFlags.None);
bConnected = mySocket.Connected;

bConnected est toujours égal à true, et l'appel revient toujours avec succès, même si le câble Ethernet a été débranché.

De plus, et malheureusement == l'envoi de données réelles ne détecte pas non plus la rupture de la connexion.

buffer[0] = 0xff ;
int iSent = mySocket.Send(buffer, 1, SocketFlags.None);

renvoie à plusieurs reprises la valeur 1, comme si elle avait réellement envoyé quelque chose. Alors que l'appareil en question n'est même plus connecté.

1voto

ng5000 Points 4556

En général, on utilise la méthode Socket.Select pour déterminer l'état d'un ensemble de sockets (Socket.Poll pour un seul socket).

Ces deux méthodes vous permettent d'interroger l'état d'une socket. Maintenant, en supposant que vous avez suivi la connexion de la socket en premier lieu, vous appelez typiquement Select/Poll sur la socket avant de tenter une lecture. Si Select/Poll indique que la socket est lisible, cela vous indique que :

  • Soit la socket a des données disponibles à la lecture, auquel cas Receive retournera les données disponibles à la lecture.
  • La socket a été fermée, dans ce cas, lorsque vous appelez Receive, 0 octet sera renvoyé immédiatement (c'est-à-dire que si Select/Poll indique que la socket est lisible et que vous appelez Receive mais qu'il renvoie immédiatement 0 octet, vous savez que la connexion a été fermée, réinitialisée ou terminée.

Personnellement, je n'ai jamais utilisé Poll - j'ai toujours utilisé Select mais MSDN semble suggérer que Poll est à peu près la même chose que Select mais pour des sockets uniques.

J'ajouterai également que, dans la plupart des cas, l'utilisation de Select est la manière la plus efficace et la meilleure de gérer les connexions Socket.

1voto

EJP Points 113412

Je ne comprends pas vraiment sa déclaration concernant l'appel de Receive() pour s'assurer que le point de terminaison distant a bien reçu toutes les données que j'ai envoyées.

Le message de @PeteDuniho ne concerne pas l'établissement de l'état de la connexion, mais la fin de la connexion de manière à ce que vous sachiez quand le pair a reçu toutes vos données.

(Les sockets bloquent-ils la réception jusqu'à ce que le tampon d'envoi soit vide ?)

Non, mais si vous fermez la socket et lisez ensuite jusqu'à EOS, vous attendez que le pair lise toutes les données jusqu'à ce que il obtient EOS et ferme ensuite le socket. Vous avez donc la garantie que toutes les données ont été transmises à l'application homologue.

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