none
Server - Socket - Thread Probleme RRS feed

  • Frage

  • Hallo,
    ich habe folgende Struktur.

    Einen Server - Thread
    Da empfange ich die Daten als String.
    Diese übergebe ich einer Read Funktion.
    Diese wiederum löst einen Event aus, an ein anderes Objekt.
    Dieses Objekt entscheidet dann was zu tun ist.

    Jetzt kommen teils Exceptions bezgl. Thread.

    Was kann ich tun, dass der empfangene Inhalt im korrekten Thread empfangen wird.
    Was muss ich machen?
    Invoke, da komme ich nicht weiter und benötige Unterstützung.

    Das Objekt MES beihaltet den BUS (Socketverbindung)

    Daten kommen rein

      ReadEvent (über Socket)

        Switch

        case 1: Write (Antwort wird gesendet)

    Danke + Grüße Andreas

     public override void Read(string data, int size, int bytesRead)
    
      {
    
       int iExecThread = System.Threading.Thread.CurrentThread.ManagedThreadId;
    
       System.Diagnostics.Trace.WriteLine("BUSSOCKET Read Thread ID " + iExecThread.ToString());
    
       
    
       System.Diagnostics.Trace.WriteLine(data);
    
       EventHandlerContentReceived(data);
    
      }
    
      
    
    
    
      public override void Init()
    
      {
    
       int iExecThread = System.Threading.Thread.CurrentThread.ManagedThreadId;
    
       System.Diagnostics.Trace.WriteLine("BUSSOCKET Init Thread ID " + iExecThread.ToString());
    
    
    
      public override void Read(string data, int size, int bytesRead)
    
      {
    
       int iExecThread = System.Threading.Thread.CurrentThread.ManagedThreadId;
    
       System.Diagnostics.Trace.WriteLine("BUSSOCKET Read Thread ID " + iExecThread.ToString());
    
       System.Diagnostics.Trace.WriteLine(data);
    
       EventHandlerContentReceived(data);
    
      }
    
    
    
    
    
    BUSSOCKET Init Thread ID 10
    
    BUSSOCKET ReceiveHandler Thread ID 17
    
    
    
    try
    
        {
    
         buffer = new byte[maxBuffer];
    
         received = socket.Receive(buffer);
    
         if (received == 0)
    
         {
    
          if (socket != null)
    
           socket.Close();
    
          if (tcpListener != null)
    
           tcpListener.Stop();
    
    
    
         }
    
         UTF8Encoding encoding = new UTF8Encoding();
    
         empfangen = encoding.GetString(buffer, 0, received);
    
         System.Diagnostics.Trace.WriteLine("Vom Client empfangen : \"" + empfangen + "\"");
    
    
    
         int iExecThread = System.Threading.Thread.CurrentThread.ManagedThreadId;
    
         System.Diagnostics.Trace.WriteLine("BUSSOCKET ReceiveHandler Thread ID " + iExecThread.ToString());
    
    
    
    
    
         Read(empfangen, 44, 22);
    
    

     

    Donnerstag, 24. Februar 2011 16:56

Antworten

  • Hallo Andreas,

    kannst Du mir denn Dein Projekt nicht einfach zukommen lassen?
    Eh ich alle momentan nicht geposteten Teile als Vermutung annehme ist es denke ich so besser.
    Und ja - auch ohne Forms würde ich das gerne mit Neuverbinden machen - am besten, der Benutzer muss so wenig wie möglich (nötig) tun. Am besten noch den Server automatisch "finden" (etwa mit WS-Discovery, natürlich sehr einfach mit WCF 4.0)

    PostAddFranksSeitePunktDE


    ciao Frank
    Donnerstag, 3. März 2011 19:18

Alle Antworten

  • Hallo Andreas,

          > Jetzt kommen teils Exceptions bezgl. Thread.

    Könnte an folgendem liegen:  [Illegal Cross Thread Call]
    http://www.yoda.arachsys.com/csharp/threads/winforms.shtml
     

    ich denke, es ist aber vorteilhaft, wenn Du ein kleines minimales Projekt zur Verfügung stellst, wo der Fehler reproduzierbar ist. Ggf. auch an meine private Mail Adresse PostAddFranksSeitePunktDe.

          > Was kann ich tun, dass der empfangene Inhalt im korrekten Thread empfangen wird.

    Normalerweise geht das über Invoke etc.
    [Threadsicheres Aufrufen von Windows Forms-Steuerelementen]


    ciao Frank

    Donnerstag, 24. Februar 2011 19:38
  • Hallo Frank,

    ja Du hast wieder Recht. Das Projekt ist schwierig. Herauszukapseln auch.

    http://www1.minpic.de/bild_anzeigen.php?id=139253&key=4033957&ende

    Hauptsächlich kommt es vor, wenn ich was empfange, je nachdem was ich empfange UI Controls update.

    Das darf ich wohl nicht.

    Wie schon mal gesagt ich brauche Deine Klasse als Server. Vielleicht siehst Du was. Ich habe es adaptiert, aber irgendwas scheint falsch zu sein.

    Suche bitte nach dem  /// HIER KNALLT ES!!!!!!  Kannst Du mal das und Deiner Serverklasse anschauen. Für den Server brauche ich kein UI,

    wie in Deinem Beispiel.

    Read sendet dann einen Event an die logische Klasse, wo der Inhalt ausgewertert wird.

        public override void Read(string data, int size, int bytesRead)
            {
                int iExecThread = System.Threading.Thread.CurrentThread.ManagedThreadId;
                System.Diagnostics.Trace.WriteLine("BUSSOCKET Read Thread ID " + iExecThread.ToString());

                System.Diagnostics.Trace.WriteLine(data);
                EventHandlerContentReceived(data);
            }

     void Bussystem_EvHaContentReceived(object sender, NotifyEventArgs e)
        {
          int iExecThread2 = System.Threading.Thread.CurrentThread.ManagedThreadId;
    
          string toAnalysis = e.NotifyMessage;
          //throw new NotImplementedException();
          // System.Windows.Forms.MessageBox.Show(toAnalysis, "Test" );
    
          if (toAnalysis == "WorkingPos")
          {
            //WorkingPos2();
            State = StateProcessWorkflow.PanelAtWorkingPos;
    
            //string s1 = ssssss_111();
            Bussystem.Write("TestAntwort", 55);
          }
        }
    

     Read sendet einen Event an das UserInterface.

     void BMES_EvHaStateOfMES(object sender, NotifyEventArgs e)
        {
          //txtStateMES.Text = e.NotifyMessage;  /// HIER KNALLT ES!!!!!!
      }
    

      

    Klasse Empfang

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;
    using System.Diagnostics;
    
    using RCommunication.Definitions.Core;
    //using RCommunication.Implementations.MES.OpCon.Core;
    //using RCommunication.Implementations.MES.OpCon;
    
    namespace RCommunication.Implementations.BUS.Socket.Core
    {
      public class BUSSocket : BaseBUS
      {
        Properties.Settings Props = Properties.Settings.Default;
        System.Net.Sockets.Socket socket;
        TcpListener tcpListener;
        const int maxBuffer = 100;
        Thread thread;
    
        /// <summary>Um den Server sauber unterbrechen zu können.
        /// Hiermit wird signalisiert, dass der Thread beenden soll.</summary>
        ManualResetEvent threadStopEvent = new ManualResetEvent(false);
    
        public override void Close()
        {
          //if (socket != null)
          //  socket.Close();
          //if (tcpListener != null)
          //  tcpListener.Stop();
    
          threadStopEvent.Set();
    
          Thread.Sleep(50);
    
          while (thread.IsAlive)
            Thread.Sleep(10);
    
          if (socket != null)
            socket.Close();
    
          if (tcpListener != null)
            tcpListener.Stop();
    
          Environment.Exit(0);
        }
    
        public override void Init()
        {
          NeuVerbinden();
    
          int iExecThread = System.Threading.Thread.CurrentThread.ManagedThreadId;
          System.Diagnostics.Trace.WriteLine("BUSSOCKET Init Thread ID " + iExecThread.ToString());
    
          try
          {
            thread = new Thread(new ThreadStart(Execute));
            thread.Start();
          }
          catch (Exception exp)
          {
            // System.Diagnostics.Trace.WriteLine(exp.Message);
          }
        }
    
    
        private void NeuVerbinden()
        {
          IPAddress ipAdresse = null;
          try
          {
            GetIpAdresse(ref ipAdresse, Dns.GetHostName());
            tcpListener = new TcpListener(ipAdresse, Props.Port);
            tcpListener.Start();
          }
          catch (Exception exp)
          {
            System.Diagnostics.Trace.WriteLine("Beim Versuch der Auflösung der Addresse: " +
             ipAdresse.ToString() + " enstand folgender Fehler:\r\n" +
             exp.Message);
            return;
          }
        }
    
        ~BUSSocket()
        {
    
        }
    
        //void Read(string msg)
        //{
        //  txtMeldung.Invoke(new ServerTextCallback(ServerText),
        //    new object[] { msg + "\r\n" });
        //  Thread.Sleep(5);
        //}
    
        //public delegate void ServerTextCallback(string text);
        //void ServerText(string text)
        //{
        //  EventHandlerContentReceived(text);
        //}
    
    
        public override void Read(string data, int size, int bytesRead)
        {
          int iExecThread = System.Threading.Thread.CurrentThread.ManagedThreadId;
          System.Diagnostics.Trace.WriteLine("BUSSOCKET Read Thread ID " + iExecThread.ToString());
    
    
          System.Diagnostics.Trace.WriteLine(data);
          EventHandlerContentReceived(data);
        }
    
        public override void Write(string data, int size)
        {
          System.Diagnostics.Trace.WriteLine(data);
          //EvHaContentReceived(data);
    
          UTF8Encoding encoding = new UTF8Encoding();
          // string toSend = "ACK";
          socket.Send(encoding.GetBytes(data));
          System.Diagnostics.Trace.WriteLine("\r\nSende \"" + data + "\" - Meldung");
        }
    
        private IPAddress GetIpAdresse(ref IPAddress ipAdresse, string hostName)
        {
          IPAddress[] ipAdressen = Dns.GetHostEntry(hostName).AddressList;
          foreach (IPAddress ip in ipAdressen)
          {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
              ipAdresse = ip;
              break;
            }
          }
    
          if (ipAdresse == null)
            throw new Exception("Keine IPV4-IP auflösbar.");
    
          return ipAdresse;
        }
    
        private void Execute()
        {
          System.Diagnostics.Trace.WriteLine("Der Server ist gestartet auf Port : " + Props.Port);
          System.Diagnostics.Trace.WriteLine("Der lokale Endpunkt ist :" + tcpListener.LocalEndpoint);
          System.Diagnostics.Trace.WriteLine("Warte auf Verbindung eines Clients ...");
          while (!this.threadStopEvent.WaitOne(0, true))
          {
            Thread.Sleep(0);
            try
            {
              if (tcpListener.Pending())
              {
                socket = tcpListener.AcceptSocket();
                System.Diagnostics.Trace.WriteLine("Client-Verbindung akzeptiert von: " +
                 socket.RemoteEndPoint);
                new Thread(new ThreadStart(ReceiveHandler)).Start();
              }
            }
            catch (Exception e)
            {
              //"Der Client wurde zum Beispiel geschlossen" -> Neuverbinden
              System.Diagnostics.Trace.WriteLine(e.Message);
            }
          }
        }
    
        void ReceiveHandler()
        {
          int received = 0;
          byte[] buffer;
          string empfangen;
    
          do
          {
            try
            {
              buffer = new byte[maxBuffer];
              received = socket.Receive(buffer);
              if (received == 0)
              {
                if (socket != null)
                  socket.Close();
                if (tcpListener != null)
                  tcpListener.Stop();
    
                return;
    
                // Application.Exit(); return;
                // wenn der Client "" sendet, soll der Server beenden. (nur als Beispiel)
              }
              UTF8Encoding encoding = new UTF8Encoding();
              empfangen = encoding.GetString(buffer, 0, received);
              System.Diagnostics.Trace.WriteLine("Vom Client empfangen : \"" + empfangen + "\"");
    
              int iExecThread = System.Threading.Thread.CurrentThread.ManagedThreadId;
              System.Diagnostics.Trace.WriteLine("BUSSOCKET ReceiveHandler Thread ID " + iExecThread.ToString());
    
              if ( empfangen.Length > 1 )
                 Read(empfangen, 44, 22);
              //string toSend = "ACK";
              //socket.Send(encoding.GetBytes(toSend));
              //System.Diagnostics.Trace.WriteLine("\r\nSende \"" + toSend + "\" - Meldung");
            }
            catch (Exception exp)
            {
              System.Diagnostics.Trace.WriteLine(exp.Message);
            }
          }
          while (received != 0);
        }
      }
    }
    Donnerstag, 24. Februar 2011 20:20
  • Hallo Frank,

    das Problem ist vielleicht gegenüber Deinem Beispiel.

    Ich empfange eine Anfrage vom Client. Sende nicht sofort eine Antwort.

    Diese gilt es woanders zu analysieren. Je nachdem muss ich was senden und den Status visualisieren.

    Alles muss natürlich im Hintergrund laufen, deshalb richtig Thread für den Server.

    Du hast wie Immer! Recht.   Das geht!

     

    void BMES_EvHaStateOfMES(object sender, NotifyEventArgs e) 
    { 
     txtStateMES.Invoke(new Action<string>(s => { txtStateMES.Text = s; }), "meine Info" + e.NotifyMessage); 
     }
    
    

    http://dzaebel.net/ControlInvoke.htm

    4 Bitten an Dich

    1) Kannst Du mir das in wenigen Worten erklären, warum das ohne Meldung geht? Was passiert da?

    2) Die Variante - Funktionszeiger

       textBox1.Invoke(new UpdateTextCallback(this.UpdateText);

      public delegate void UpdateTextCallback(string text);
      private void UpdateText(string text)
      {
        textBox1.Text = text;
      }

    3 ) Ohne Invoke, mit BackgroundWorker, da macht der Backgound alles, oder? Da wird ja der Textbox nichts großes gemacht, eigentlich normal.

    4) GANZ WICHTIG, habe ich Deinen Server korrekt gekapselt ohne UserInterface, ohne Forms.

    Bitte querchecken und Danke.

    Grüße Andreas

    Donnerstag, 24. Februar 2011 20:26
  • 4) GANZ WICHTIG, habe ich Deinen Server korrekt gekapselt ohne UserInterface, ohne Forms.

    Hallo Frank,

    hast Du noch einen Tipp, wenigstens zum obigen?

    Wie würdest Du da u.a. Neuverbinden machen? Also ohne Forms.

    Danke.

    Grüße Andreas

    Sonntag, 27. Februar 2011 09:16
  • Hallo Andreas,

    kannst Du mir denn Dein Projekt nicht einfach zukommen lassen?
    Eh ich alle momentan nicht geposteten Teile als Vermutung annehme ist es denke ich so besser.
    Und ja - auch ohne Forms würde ich das gerne mit Neuverbinden machen - am besten, der Benutzer muss so wenig wie möglich (nötig) tun. Am besten noch den Server automatisch "finden" (etwa mit WS-Discovery, natürlich sehr einfach mit WCF 4.0)

    PostAddFranksSeitePunktDE


    ciao Frank
    Donnerstag, 3. März 2011 19:18