Timeout TCP sur les sockets [Résolu]

shackleton1986 9 Messages postés jeudi 12 janvier 2006Date d'inscription 21 mars 2007 Dernière intervention - 19 mars 2007 à 15:13 - Dernière réponse : shackleton1986 9 Messages postés jeudi 12 janvier 2006Date d'inscription 21 mars 2007 Dernière intervention
- 21 mars 2007 à 14:01
Je suis en train de faire des tests sur les sockets TCP dans le framework 2.0 et j'ai remarqué quelque chose d'assez curieux...
Je voulais savoir à quel niveau sont renvoyés les exceptions typiquement lorsqu'un cable réseau est arraché ou autre. Pour tester, j'utilise un client telnet sur un PC pour ouvrir un socket avec mon serveur dont le code est ci-dessous. Tout de suite après je déconnecte le PC client du réseau (j'enlève le cable à la barbare ^^), puis je fais des sleep pendant un certain temps voir si j'ai une exception qui est remontée par le framework.
Jusque là, pas d'exception alors que la pile TCP a du se vautrer en raison de l'absence du client qui a été déconnecté sauvagement :) Là je me dis c'est normal, j'aurais une exception la prochaine fois que je veu utiliser mon socket. Du coup je tente de faire un send ... et bingo !!! Aucune exception et le retour du send me dit qu'il a bien envoyé ces octets :s J'essaye même de regarder la valeur "connected" du socket pour voir si j'ai bien quelqu'un en face et il me dit que oui ... :(
Bref, voila mon problème : comment savoir si j'ai toujours quelqu'un en face avec le .net framework ? Et surtout comment savoir quand il me dit que mes données ont bien été envoyées (retour du send) alors que c'est pas le cas ??

Par la suite j'ai essayé d'utiliser la variable SendTimeout du socket mais ca n'a rien changé ...

Voici le code tout bête de mon serveur TCP pour que vous voyez exactement ce que je fais :

Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text

Public Class Form1
    Dim port As Integer = 10000

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim sckListening As Socket
        Dim sckClient As Socket

        sckListening = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        sckListening.Bind(New IPEndPoint(IPAddress.Any, port))
        sckListening.Listen(5)
        System.Console.WriteLine("Socket en écoute sur " & sckListening.LocalEndPoint.ToString)
        sckClient = sckListening.Accept()
        System.Console.WriteLine("Serveur: Connexion acceptée avec " & sckClient.RemoteEndPoint.ToString)

       'On règle le sois-disant timeout TCP pour l'envoi
        sckClient.SendTimeout = 1000

       'Là en gros on dort pendant 50 sec pendant qu'on arrache (gentiment) le cable du client
       'A chaque sleep on affiche la variable Connected du socket pour voir s'il ya toujours
       'quelqu'un en face
        Dim i As Integer
        For i = 0 To 9
            System.Console.WriteLine("Attente de plantage ... " & CStr((i + 1) * 5) & "sec")
            System.Console.WriteLine("Socket connecté ? " & sckClient.Connected.ToString)
            Threading.Thread.Sleep(5000)
        Next

       'Maintenant on envoi 6 octets sur le socket qui est mort pour voir si on récupère une
       'exception
        Dim nbByte As Integer
        nbByte = sckClient.Send(Encoding.ASCII.GetBytes("bijour"), 6, SocketFlags.None)
        System.Console.WriteLine(CStr(nbByte))
   
       'On a eut aucune exception et la fonction send a envoyer son retour immédiatement
       'Mais on fait des sleeps en se disant que le SendTimeout va peut être nous générer
       'une exception plus tard
        For i = 0 To 9
            System.Console.WriteLine("Attente de plantage ... " & CStr((i + 1) * 5) & "sec")
            System.Console.WriteLine("Socket connecté ? " & sckClient.Connected.ToString)
            Threading.Thread.Sleep(5000)
        Next

       'Et voilà c'est fini, et on a envoyé des données comme si de rien n'était à un client inexistant
        System.Console.WriteLine("Fin")
    End Sub
End Class

Merci d'avances pour vos réponses :)
Afficher la suite 

5 réponses

Répondre au sujet
Egyde 161 Messages postés lundi 17 mai 2004Date d'inscription 16 juillet 2007 Dernière intervention - 20 mars 2007 à 00:26
+3
Utile
Intéressant tout ça... J'ai jamais rencontré ce pb (vu que je programme que sous VB6 pour le moment). Cela dit, j'ai trouvé quelques infos qui pourront t'aider certainement. Apparemment, c'est un bug connu chez KroKro :
http://dam.mellis.org/2004/08/net_socket_bugs_gotchas/

@+
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Egyde
shackleton1986 9 Messages postés jeudi 12 janvier 2006Date d'inscription 21 mars 2007 Dernière intervention - 20 mars 2007 à 08:54
0
Utile
Merci beaucoup pour ta réponse, c'est quand même hallucinant ces bugs ...
Je vais essayer de voir comment je peu me débrouiller avec .NET ^^
Je trouve ca dingue que des bugs si importants restent sans correctif --> merci Crosoft :p

En tout cas si quelqu'un a une bidouille pour repérer les déco intempestives de socket je suis preneur !!!
Commenter la réponse de shackleton1986
shackleton1986 9 Messages postés jeudi 12 janvier 2006Date d'inscription 21 mars 2007 Dernière intervention - 21 mars 2007 à 09:10
0
Utile
J'ai posée ma question sur les newsgroups US de Microsoft et j'ai obtenu la réponse suivante :

It can take time to acknowledge that the socket connection is really broken.


It's not instant measure.



From the VS2005 documentation:


"


A successful completion of the Send method means that the underlying system


has had room to buffer your data for a network send.


..


..


..


The successful completion of a send does not indicate that the data was


successfully delivered.


"



I use this on our apps to check quite reliably that the socket is open on


both ends or not:



        private static bool IsSocketReallyConnected(Socket socket)


        {


            bool retState = false;


            bool blockingState = socket.Blocking;


            try


            {


                byte[] tmp = new byte[1];



                socket.Blocking = false;


                socket.Send(tmp, 0, 0);


                retState = true;


            }


            catch (SocketException e)


            {


                // 10035 == WSAEWOULDBLOCK -> Buffer full for now


                if (e.NativeErrorCode.Equals(10035))


                {


                    retState = true;


                }


            }


            finally


            {


                socket.Blocking = blockingState;


            }



            return retState;


        }



And it's not a bug

Apparement ce n'est pas un bug mais plutôt une "feature" comme dirait un ami à moi ^^ J'ai pas encore testé ce bout de code mais je trouve ca complètement naze que le send soit pas bloquant et qu'on soit obligé de s'écrire une fonction de 20 lignes sortie de derrière les bois pour savoir si son socket est ouvert ...
Commenter la réponse de shackleton1986
Egyde 161 Messages postés lundi 17 mai 2004Date d'inscription 16 juillet 2007 Dernière intervention - 21 mars 2007 à 12:55
0
Utile
Que Send n'indique pas la réception correcte des données passe encore. En y réfléchissant bien, ça accélère le trafic dans le sens où on attend pas de confirmation de la part du poste distant.

Mais par curiosité, comme ce n'est visiblement pas l'état courant du socket, j'aimerais bien savoir ce que retourne exactement sckClient.Connected...
Commenter la réponse de Egyde
shackleton1986 9 Messages postés jeudi 12 janvier 2006Date d'inscription 21 mars 2007 Dernière intervention - 21 mars 2007 à 14:01
0
Utile
Je suis d'accord avec toi, on peut encore accepter que send indique juste que les données on bien été mises dans le tampon. Mais je me demande alors a quoi sert la variable sckClient.Blocking qui par défaut est à True ?? Parcqu'à priori ca ne change rienà première vue. En ce qui concerne le sckClient.connected je ne comprend toujours pas son utilité...

Je me suis un peu penché sur sur la pile TCP windows et il apparait que par défaut, ce n'est qu'au bout de 2 heures (KeepAliveTime) que des "retransmissions" sont effectuées pour tester la présence du tiers distant. Du coup jusqu'à ce timeout la connexion TCP est considéré active par la pile TCP et donc par le Framework. On peut donc simplement s'en aperçevoir quand le tampon est plein et que l'on obtient une exception. Enfin, c'est ce que je pense mais il faut encore que je fasse quelques tests

Je vous tiendrai au courant de mes investigations
Commenter la réponse de shackleton1986

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.