Meilleur auteur de réponses
Socket Serveur Asynchrone

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/>
handler.BeginReceive(state.buffer = new byte [handler.Available], 0, handler.Available, SocketFlags.None, new AsyncCallback(ReadCallback), state); <br/>
Je reste a votre disposition pour toute information complementaire.
Cordialement,
GJean
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- Marqué comme réponse Gilles TOURREAUModerator vendredi 21 août 2009 19:54
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# -
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 -
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- Marqué comme réponse Gilles TOURREAUModerator vendredi 21 août 2009 19:54
-
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
Mon code ne doit pas etre tres beau mais ca marche.
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; } } } }
Merci pour les explications donnée.
Cordialement,
GJean