Comment savoir quand un socket a été déconnecté

Du côté du client, j’ai besoin de savoir quand / si ma connexion de socket a été rompue. Cependant, la propriété Socket.Connected renvoie toujours la valeur true, même après la déconnexion du côté serveur et après avoir essayé d’envoyer des données par son intermédiaire. Quelqu’un peut-il m’aider à comprendre ce qui se passe ici? J’ai besoin de savoir quand un socket a été déconnecté.

Socket serverSocket = null; TcpListener listener = new TcpListener(1530); listener.Start(); listener.BeginAcceptSocket(new AsyncCallback(delegate(IAsyncResult result) { Debug.WriteLine("ACCEPTING SOCKET CONNECTION"); TcpListener currentListener = (TcpListener)result.AsyncState; serverSocket = currentListener.EndAcceptSocket(result); }), listener); Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, and it is clientSocket.Connect("localhost", 1530); Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be TRUE, and it is Thread.Sleep(1000); serverSocket.Close();//closing the server socket here Thread.Sleep(1000); clientSocket.Send(new byte[0]);//sending data should cause the socket to update its Connected property. Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, but its always TRUE 

Après quelques tests, il apparaît que la documentation de Socket.Connected est erronée, ou du moins trompeuse. clientSocket.Connected deviendra faux uniquement après l’ clientSocket.close() de clientSocket.close() . Je pense qu’il s’agit d’un retour à l’API originale des sockets C Berkeley et de sa terminologie. Une socket est liée lorsqu’elle est associée à une adresse locale et une socket est connectée à une adresse distante. Même si le côté distant a fermé la connexion, la prise locale a toujours l’association et rest donc “connectée”.

Cependant, voici une méthode qui fonctionne:

 !(socket.Poll(0, SelectMode.SelectRead) && socket.Available == 0) 

Il se base sur ce fait qu’une connexion fermée sera marquée comme lisible bien qu’aucune donnée ne soit disponible.

Si vous souhaitez détecter des conditions telles que des câbles réseau cassés ou des ordinateurs éteints brusquement, la situation est un peu plus complexe. Dans ces conditions, votre ordinateur ne reçoit jamais de paquet indiquant que le socket est fermé. Il doit détecter que le côté distant a disparu en envoyant des paquets et en remarquant qu’aucune réponse ne revient. Vous pouvez le faire au niveau de l’application dans le cadre de votre protocole ou utiliser l’option TCP KeepAlive. Utiliser TCP Keep Alive à partir de .NET n’est pas particulièrement facile. vous feriez probablement mieux de créer un mécanisme de maintien de la vie dans votre protocole (vous pouvez également poser une question distincte pour “Comment activer TCP Garder en vie dans .NET et définir un intervalle de maintien en vie?”).

Il suffit d’écrire sur votre socket comme d’habitude. Vous saurez quand il est déconnecté par l’exception qui indique que vos données ne peuvent pas être livrées.

Si vous n’avez rien à écrire … alors qui se soucie de savoir si c’est déconnecté? Il est peut-être déconnecté maintenant, mais revenez-y avant que vous en ayez besoin – pourquoi vous embêtez de le briser, puis en boucle pour vous reconnecter jusqu’à ce que le lien soit réparé … surtout quand vous n’aviez rien à dire de toute façon?

Si cela vous dérange, implémentez un Keep Alive dans votre protocole. Ensuite, vous aurez quelque chose à dire toutes les 30 secondes environ.

Peut-être que la solution consiste à envoyer des données factices et à vérifier si le délai est dépassé?

Je recommande de supprimer les éléments de langage de niveau supérieur et d’explorer ce qui se passe aux IO de niveau inférieur.

Le plus bas que j’ai exploré était en écrivant isectd (trouver sur sourceforge). À l’aide de l’appel système select (), un descripteur de socket fermé devient prêt à la lecture et, lorsque isectd tente d’essayer recv (), l’état de déconnexion du socket peut être confirmé.

En guise de solution, je vous recommande de ne pas écrire votre propre socket IO et d’utiliser le middleware de quelqu’un d’autre. Il y a beaucoup de bons candidats. N’oubliez pas de prendre également en compte les services de mise en queue simples.

PS J’aurais fourni des URL à tout ce qui précède mais ma réputation (1) ne le permet pas.

la méthode clientSocket.Send () attend-elle que le paquet soit acquit / renvoyé?

Si ce n’est pas le cas, votre code vole sur la ligne suivante, alors que socket tente encore de comprendre ce qui se passe.