2016-12-09 4 views
0

J'ai affaire à la programmation socket, mais j'ai quelques problèmes au sujet du mécanisme d'enfilage. En fait, c'est un gros point d'interrogation sur ma tête. Tout d'abord, j'ai une classe UDPListener que je peux recevoir les données provenant de certains clients sur le réseau. En outre, je mets un gestionnaire d'événement dans cette classe, je veux invoquer une zone de texte lorsque les données sont reçues simultanément.Données asynchrones provenant de la socket udp dans TextBox Simultanément

 class udpListener 
     {  
      private static int portNumber = 9081; 
      private UdpClient udp = new UdpClient(portNumber); 
      private bool isend = false; 
      public volatile int CountOfReceived = 0; 
      public List<string> messageList = new List<string>(); 
      public List<string> ipList = new List<string>(); 
      public bool isClientClosed = false; 
      messageReceivedEventArgs mre=new messageReceivedEventArgs(); 

     public void StartListening() 
     { 
      udp.BeginReceive(Receive, new object()); //BeginReceive must be completed by calling EndReceive method 
     } 

     private void Receive(IAsyncResult ar) 
     { 
      if (udp.Client == null) 
       return; 
      Interlocked.Increment(ref CountOfReceived); 

      IPEndPoint ip = new IPEndPoint(IPAddress.Any, portNumber); 
      byte[] bytes = udp.EndReceive(ar, ref ip); //Ends a pending asynchronous receive 

      if (bytes.Length > 0) 
      { 
       mre.isMessageReceived = true; 
       mre.message = Encoding.ASCII.GetString(bytes); 
      } 
      else 
       mre.isMessageReceived = false; 

      controlMessageReceived(); 
      string message = Encoding.ASCII.GetString(bytes); 
      string[] seperator = {"|"}; 
      string[] array = message.Split(seperator, StringSplitOptions.RemoveEmptyEntries); 
      messageList.Add(array[0]); 
      ipList.Add(ip.Address.ToString()); 
      Console.WriteLine(message); 
      StartListening();  
     } 

     public void closeSocket() 
     { 
      if (udp.Client != null) 
       udp.Close(); 
     } 

     private void controlMessageReceived() 
     { 
      if(mre.isMessageReceived) 
       handler(this,mre); 
     } 

     public event EventHandler<messageReceivedEventArgs> handler; 


    } 

    public class messageReceivedEventArgs:EventArgs 
    { 
     public bool isMessageReceived { get; set; } 
     public string message {get;set;} 
    } 

Comme vous pouvez le voir, quand bytes.length plus grand que zéro, je suppose que oui, les données sont reçues et maintenant je dois appeler pour transférer textbox ces données en zone de texte.

je teste simplement ce scénario avec un buttoneventhandler dans thread principal

public partial class Form1 : Form 
    { 
    public Form1() 
    { 
     InitializeComponent(); 
    } 


    private void button1_Click(object sender, EventArgs e) 
    { 

     networkInterface ni = new networkInterface(); 

     udpSender UDPSender = new udpSender(); 
     udpListener UDPListener = new udpListener(); 

     IPAddress braddress = ni.GetBroadcastAddress(ni.GetDefaultGateway(), ni.GetSubnetMask()); 
     UDPSender.Send(braddress, "somedatahere"); 
     Thread.Sleep(2000); 
     UDPListener.StartListening(); 
     UDPListener.handler += appendTextBox; 


    }  

    private void appendTextBox(object sender, messageReceivedEventArgs e) 
    { 
     textBox1.Text += e.message; 

    } 
} 

Je stocker ces messages dans une liste de chaînes et je voudrais après socket est fermée lire que les données de cette zone de liste, mais il est si difficile et une façon non professionnelle de le faire, je veux avoir ces données dans la zone de texte pendant qu'ils sont encore reçus par le serveur. Je sais que ma zone de texte est dans le thread principal et la méthode appendtext appartient au thread Asynchrone, et il n'est pas permis d'accéder à cette zone de texte à partir d'un autre thread, mais je ne sais pas comment le faire. obtenir ce que je désire.

Voici la solution comment je résoudre ce problème, grâce à @Troy Mac1ure

public partial class Form1 : Form 
    { 

    public delegate void UpdateTextCallback(string s); 
    public Form1() 
    { 
     InitializeComponent(); 
    } 


    private void button1_Click(object sender, EventArgs e) 
    { 
     networkInterface ni = new networkInterface(); 

     udpSender UDPSender = new udpSender(); 
     udpListener UDPListener = new udpListener(); 

     IPAddress braddress = ni.GetBroadcastAddress(ni.GetDefaultGateway(), ni.GetSubnetMask()); 
     UDPSender.Send(braddress, "gr|smartrc"); 
     Thread.Sleep(2000); 
     UDPListener.StartListening(); 
     UDPListener.handler += appendTextBox;  

    } 

    private void appendTextBox(object sender, messageReceivedEventArgs e) 
    { 
     if (textBox1.InvokeRequired) 
     { 
      textBox1.Invoke(new UpdateTextCallback(addTextBox), new object[] { e.message }); // invoking itself 
     } 
     else 
     { 
      textBox1.Text += e.message; 
     }  
    } 

    private void addTextBox(string text) 
    { 
     textBox1.Text += text; 
    } 
} 

Répondre

0

Vous pouvez forcer la mise à jour se produire sur le thread principal par lui-même invoquer. Il existe plusieurs façons de déclarer et d'exécuter cette tâche. Voici un:

public delegate void UpdateTextCallback(object sender, messageReceivedEventArgs e); 

private void appendTextBox(object sender, messageReceivedEventArgs e) 
{ 
     if (textBox1.InvokeRequired) 
     { 
      listBox1.Invoke(new UpdateTextCallback(appendTextBox), new object[] { sender, e }); // invoking itself 
     } 
     else 
     { 
      textBox1.Text += e.message; 
     } 
} 
+0

Merci pour votre réponse rapide, mais je ne comprends pas comment cela fonctionne, d'une part mon gestionnaire d'événements appelle appndTextBox, puis un autre délégué qui appartient à thread principal essayez d'appeler la zone de texte, suis-je raison? En outre, ce nouveau type de délégué et la méthode appendTextBox ne correspondent pas, après avoir modifié le délégué UpdateTextCallback au type de méthode appendTextBox, je ne peux plus lire aucune donnée. – arkbrk

+0

J'ai modifié la délégation à une autre méthode, j'ai ajouté la nouvelle solution sur ma question, maintenant je peux lire les données, mais c'est un peu difficile à comprendre, pouvez-vous s'il vous plaît me corriger si je me trompe. Tout d'abord, j'ai invoqué AppendTextBox à partir du thread Asynchrone avec eventhandler, puis dans appendTextBox j'ai appelé une autre méthode avec un nouveau délégué qui appartient à la méthode principale, donc il n'y a pas de problème crossthread, est-ce vrai? En outre, comment textbox1.InvokeRequired savoir si textbox1 est tenté d'invoquer? Je comprends exactement le concept de celui-ci. Enfin, j'apprécie vraiment pour votre aide. – arkbrk

+0

InvokeRequired vérifie si le contrôle est en cours d'accès sur le thread d'origine. Si ce n'est pas le cas, il appelle la fonction pour s'exécuter sur le thread d'origine, donc vous aurez deux fonctions appendTextBox() en cours d'exécution en même temps. La première fonction (exécutée dans votre nouveau thread) va juste quitter après avoir appelé la seconde (exécutée dans le Thread original) et la seconde mettra à jour votre zone de texte en conséquence. –