none
Socket Serveur Asynchrone RRS feed

  • Question

  • Bonjour,

    Dans le cadre de mon stage je doit réaliser une socket serveur asynchrone en C# que je decouvre en meme temps. Mais la difficulté qui ce pose a moi c'est que c'est pas le client qui va envoyer la premiere commande mais le serveur qui doit envoyer la première commande. La partie d'écoute marche. et l'envoie par le serveur de la première commande ca passe bien aussi mais j'ai un problème sur la partie réception car si je mets pas de point d'arrêt sur la partie réception je ne réceptionne rien.

    Voila le code ou je suis partie de l'exemple socket serveur asyncrhone du MSDN :

    public
     static
     void
     StartListening()<br/>
            {<br/>
                byte
    [] bytes = new
     Byte[1024];<br/>
    <br/>
                IPEndPoint ConnexionConfig = new
     IPEndPoint(IPAddress.Any, 6011);<br/>
                Socket Listener = new
     Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);<br/>
    <br/>
                try
    <br/>
                {<br/>
                    Listener.Bind(ConnexionConfig);<br/>
                    Listener.Listen(1);<br/>
    <br/>
                    while
     (true
    )<br/>
                    {<br/>
                        allDone.Reset();<br/>
    <br/>
                        Console.WriteLine("Attente de connexion du transpondeur..."
    );<br/>
                        Listener.BeginAccept(new
     AsyncCallback(OnClientConnect), Listener);<br/>
    <br/>
                        allDone.WaitOne();<br/>
                    }<br/>
                }<br/>
                catch
     (Exception e)<br/>
                {<br/>
                    Console.WriteLine(e.ToString());<br/>
                }<br/>
                Console.WriteLine("\nPress Enter to continue..."
    );<br/>
                Console.ReadLine();<br/>
            }<br/>
            public
     static
     void
     OnClientConnect(IAsyncResult asyn)<br/>
            {<br/>
                allDone.Set();<br/>
                Socket Listener = (Socket)asyn.AsyncState;<br/>
                Socket handler = Listener.EndAccept(asyn);<br/>
    <br/>
                StateObject state = new
     StateObject();<br/>
                state.WorkSocket = handler;<br/>
                SendSelectAsk(handler);<br/>
                handler.BeginReceive(state.buffer = new
     byte
    [handler.Available], 0, handler.Available, SocketFlags.None, new
     AsyncCallback(ReadCallback), state);<br/>
                <br/>
                <br/>
            }<br/>
    <br/>
            public
     static
     void
     ReadCallback(IAsyncResult asyn)<br/>
            {<br/>
    <br/>
                StateObject state = (StateObject)asyn.AsyncState;<br/>
                Socket handler = state.WorkSocket;<br/>
                int
     OctetRecu = handler.EndReceive(asyn);<br/>
    <br/>
                Reponse = TraitementAPDU.APDU_Select_Application.Reception_APDU_Select(state.buffer);<br/>
                Console.WriteLine(Reponse);<br/>
               <br/>
                    <br/>
                <br/>
                <br/>
                <br/>
            }<br/>
    <br/>
            public
     static
     void
     SendSelectAsk(Socket handler)<br/>
            {<br/>
                byte
    [] Requete = TraitementAPDU.APDU_Select_Application.Envoie_APDU_Select();<br/>
                handler.BeginSend(Requete, 0, Requete.Length, SocketFlags.None, new
     AsyncCallback(SendCallback), handler);<br/>
            }<br/>
    <br/>
            public
     static
     void
     SendTicketAsk(Socket handler)<br/>
            {<br/>
                byte
    [] Requete = TraitementAPDU.APDU_Select_Ticket.Envoie_APDU_Select_Ticket("00"
    );<br/>
                handler.BeginSend(Requete, 0, Requete.Length, SocketFlags.None, new
     AsyncCallback(SendCallback), handler);<br/>
            }<br/>
            private
     static
     void
     SendCallback(IAsyncResult asyn)<br/>
            {<br/>
                try
    <br/>
                {<br/>
                    <br/>
                Socket handler = (Socket) asyn.AsyncState;<br/>
                <br/>
                int
     byteSent = handler.EndSend(asyn);<br/>
                Console.WriteLine("{0} Octets envoyé au Transpondeur"
    , byteSent);<br/>
                <br/>
                }<br/>
                catch
     (Exception e)<br/>
                {<br/>
                    Console.WriteLine(e.ToString());<br/>
                }<br/>
            }<br/>
    
    
    Mon Probleme vient du faite que la commande :
    handler.BeginReceive(state.buffer = new
     byte
    [handler.Available], 0, handler.Available, SocketFlags.None, new
     AsyncCallback(ReadCallback), state); <br/>
    
    
    Cette commande ne reçoit rien. Alors que si je mets un point d'arret juste sur cette commande la je recoit les données.

    Je reste a votre disposition pour toute information complementaire.

    Cordialement,
    GJean
    mercredi 19 août 2009 08:03

Réponses

  • Bonjour,

    ManualResetEvent permet de faire "communiquer" les Thread par des "signaux". Bien évidemment, pour utiliser ManualResetEvent, il faut avoir au moins 2 Threads.
    Les principes des signaux est très simple :
    - Il faut d'abord mettre l'état du signal à non-signalé via la méthode ManualResetEvent.Reset()
    - Les threads qui doivent attendre le signal d'un autre thread doivent faire appel à la méthode ManualResetEvent.WaitOne(). Une fois cette méthode appellé, le Thread est automatiquement mis en attente.
    - Pour "réveiller" les threads mis en attente précédemment, il suffit de faire appel à la méthode ManualResetEvent.Set(). Une fois cette méthode appellé, les Thread qui étaient en attente sont automatiquement actif.
    - Il faut ensuite, manuellement réinitialiser le ManualResetEvent (via la méthode Reset()) si vous souhaitez le réutiliser.

    En espérant que ces pistes vous aideront...

    Cordialement
    Gilles TOURREAU - MVP C# - Architecte .NET/Consultant/Formateur
    jeudi 20 août 2009 20:01
    Modérateur

Toutes les réponses

  • Bonjour,

    Si vous faites un BeginReceive(), le code reprend immédiatement la main car le Receive se fera sur un autre Thread. Si le code execute rapidement ce BeginReceive() et si le paquet n'a toujours pas été reçu, c'est normal que vous ne recevez rien.
    Le fait que vous mettiez un point d'arrêt, c'est le débogueur qui ralenti l'exécution de votre programme permettant la réception de paquet au moment du BeginReceive().

    Si vous êtes débutant je vous conseille de ne pas utiliser les méthodes BeginXXXXX et EndXXXXX dans votre cas.
    Le cas le plus simple pour faire un serveur asynchrone consiste à :
    - Avoir un Thread qui s'occupe de faire des Accept() sans cesse de nouveau client.
    - Pour chaque client accepté, le serveur crée un Thread qui se charge de communiquer avec le client concerné (via de simple Receive/Send).

    Est-ce que cela vous guide un peu ?

    Cordialement
    Gilles TOURREAU - MVP C#
    mercredi 19 août 2009 20:01
    Modérateur
  • Bonjour,

    Effectivement avec un des Threads ca serait plus simple... Dans la journée hier j'ai decouvert la fonction TCPListner et NetworkStream. Ma connexion n'a pas besoin d'être asynchrone car il y'a qu'une seul connexion qui va ce créer donc pas besoin d'asynchrone. Donc ce que j'ai mit en place avec des NetworkStream.BeginRead et et BeginSend marche je récupère bien mes données mais je bloque sur l'utilisation de ManualResetEvent pour bloquer a certain moment pour que le traitement des données ce face. Alors es ce qu'il serai possible d'avoir une explication de ces fameuse ManualResetEvent car pour le moment les explications trouver ne sont pas convaincante. Ou alors trouver une facon de faire le traitement de ces données ?


    Cordialement,
    GJean
    jeudi 20 août 2009 13:27
  • Bonjour,

    ManualResetEvent permet de faire "communiquer" les Thread par des "signaux". Bien évidemment, pour utiliser ManualResetEvent, il faut avoir au moins 2 Threads.
    Les principes des signaux est très simple :
    - Il faut d'abord mettre l'état du signal à non-signalé via la méthode ManualResetEvent.Reset()
    - Les threads qui doivent attendre le signal d'un autre thread doivent faire appel à la méthode ManualResetEvent.WaitOne(). Une fois cette méthode appellé, le Thread est automatiquement mis en attente.
    - Pour "réveiller" les threads mis en attente précédemment, il suffit de faire appel à la méthode ManualResetEvent.Set(). Une fois cette méthode appellé, les Thread qui étaient en attente sont automatiquement actif.
    - Il faut ensuite, manuellement réinitialiser le ManualResetEvent (via la méthode Reset()) si vous souhaitez le réutiliser.

    En espérant que ces pistes vous aideront...

    Cordialement
    Gilles TOURREAU - MVP C# - Architecte .NET/Consultant/Formateur
    jeudi 20 août 2009 20:01
    Modérateur
  • Bonjour,

    S'ayer enfin j'ai réussit et ca marche. Voila ce que ca donne :

    class Program
        {
            public static byte[] buffer;
            public static string Reponse = "";
            public static string State;
            public static int i = 0;
    
            public static TraitementAPDU.TraitementTicket.TableauDonneeTraite[] DonneeATraite = new TraitementAPDU.TraitementTicket.TableauDonneeTraite[10];
            public static ManualResetEvent SentDone = new ManualResetEvent(false);
            public static ManualResetEvent ReadDone = new ManualResetEvent(false);
            
            static void Main(string[] args)
            {
                TcpListener server = null;
                for (int i = 0; i < 10; i++)
                {
                    DonneeATraite[i] = new TraitementAPDU.TraitementTicket.TableauDonneeTraite();
                }
                try
                {
                    IPEndPoint ConnexionConfig = new IPEndPoint(IPAddress.Any, 6011);
    
                    server = new TcpListener(ConnexionConfig);
    
                    server.Start();
    
    
    
                    Console.WriteLine("Attente de connexion du Transpondeur...");
    
                    TcpClient client = server.AcceptTcpClient();
                    Console.WriteLine("Le transpondeur est connecté !");
    
    
                    NetworkStream Stream = client.GetStream();
                    if (Stream.CanWrite)
                    {
                        SentDone.Reset();
                        State = "Select";
                        byte[] Requete = TraitementAPDU.APDU_Select_Application.Envoie_APDU_Select();
                        Stream.BeginWrite(Requete, 0, Requete.Length, new AsyncCallback(SendCallback), Stream);
                        Console.WriteLine("Requete envoyer au Transpondeur : " + Requete);
                        SentDone.WaitOne();
    
                    }
                    if (Stream.CanRead)
                    {
    
                        ReadDone.Reset();
                        buffer = new byte[212];
                        Stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), Stream);
                        ReadDone.WaitOne();
    
                    }
                    if (Reponse == "9000")
                    {
    
                        for (i = 0; i < 10; i++)
                        {
                            if (Stream.CanWrite)
                            {
                                SentDone.Reset();
                                State = "Ticket";
                                string P2 = "0" + i.ToString();
                                byte[] Requete = TraitementAPDU.APDU_Select_Ticket.Envoie_APDU_Select_Ticket(P2);
                                Stream.BeginWrite(Requete, 0, Requete.Length, new AsyncCallback(SendCallback), Stream);
                                SentDone.WaitOne();
                            }
                            if (Stream.CanRead)
                            {
                                ReadDone.Reset();
                                buffer = new byte[380];
                                Stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), Stream);
                                ReadDone.WaitOne();
                            }
                        }
                    }
                }
    
                catch (SocketException e)
                {
                    Console.WriteLine(e.ToString());
                }
                Console.Read();
            }
            private static void SendCallback(IAsyncResult asyn)
            {
    
                NetworkStream Stream = (NetworkStream)asyn.AsyncState;
                //long bytesSent = Stream.Length;
                Stream.EndWrite(asyn);
                //Console.WriteLine("{0} Octets envoyé au Transpondeur ! ", bytesSent);
                Console.WriteLine("Test Envoie");
                SentDone.Set();     
    
            }
            private static void ReadCallback(IAsyncResult asyn)
            {
                NetworkStream Stream = (NetworkStream)asyn.AsyncState;
    
                int OctetsRecu = Stream.EndRead(asyn);
    
                switch (State)
                {
                    case "Select":
                        Reponse = utils.Byte2String(buffer);
                        Reponse = TraitementAPDU.TraitementReponseRecu(Reponse);
                        Reponse = Reponse.Substring(Reponse.Length - 4);
                        Console.WriteLine("Reponse du Transpondeur : " + Reponse);
                        ReadDone.Set();
                        break;
                    case "Ticket":
    //Ce If est vraiment bizarre mais sinon ca marche pas alors je le laisse j'ai essayer de le remplacer par un While mais rien a faire alors je laisse ca comme ca pour le moment mais si il y'a une solution je prends
    if (Stream.DataAvailable == false) { Stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), Stream); break; } else { string Ticket = utils.Byte2String(buffer); Ticket = TraitementAPDU.TraitementReponseRecu(Ticket); Console.WriteLine("Reponse du Transpondeur : " + Ticket); string Ticket_ASCII = utils.convertAsciiToString(Ticket, i); Console.WriteLine("Ticket apres traitement : " + Ticket_ASCII); ReadDone.Set(); break; } } } }
    Mon code ne doit pas etre tres beau mais ca marche.

    Merci pour les explications donnée.

    Cordialement,
    GJean
    • Marqué comme réponse GJean vendredi 21 août 2009 09:31
    • Non marqué comme réponse GJean vendredi 21 août 2009 09:31
    vendredi 21 août 2009 07:17