Laden...

UDP Client dispose funktioniert nicht

Erstellt von maxwell86 vor 11 Jahren Letzter Beitrag vor 11 Jahren 2.041 Views
M
maxwell86 Themenstarter:in
32 Beiträge seit 2010
vor 11 Jahren
UDP Client dispose funktioniert nicht

Hallo Zusammen,

ich möchte per UDP eine Kommunikation mit einem Arduino-Controller herstellen. Das klappt auch wunderbar. Da ich in meiner Software erkennen will, ob ich noch verbunden bin, sendet der Arduino regelmäßig Pakete, d.h. sobal in meiner Software ein Timeout auftritt, ist der Arduino nicht mehr verbunden. Dafür habe ich folgende Methode, die in einem extra Thread aufgerufen wird:

private void doConnect()
        {
            this.EP = new IPEndPoint(this.IP, this.Port);
            while (this.connectThreadRunning)
            {
                if (!this.IsConnected)
                {
                    try
                    {
                        udpClient = new UdpClient(this.Port);
                        udpClient.Client.ReceiveTimeout = 5000;
                        udpClient.Connect(this.IP, this.Port);

                        if (!this.connectThreadRunning)
                            return;

                        Byte[] sendBytes = Encoding.ASCII.GetBytes("con");
                        udpClient.Send(sendBytes, sendBytes.Length);
                        Byte[] receiveBytes = udpClient.Receive(ref this.EP);
                        string returnData = Encoding.ASCII.GetString(receiveBytes);

                        UdpState s = new UdpState(this.EP, udpClient, this);

                        if (returnData.Contains("ack"))
                        {
                            this.IsConnected = true;
                            udpClient.Client.ReceiveTimeout = 500;
                            udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 500);
                        }
                        else
                        {
                            udpClient.Close();
                        }
                    }
                    catch (Exception exc)
                    {
                        udpClient.Close();
                    }
                }
                else
                {
                    Byte[] buf = new Byte[0];
                    try
                    {
                        buf = udpClient.Receive(ref this.EP);

                        string receiveString = Encoding.ASCII.GetString(buf);
                        String[] Messages = receiveString.Split('#');
                        if (Messages.Length == 0)
                            continue;

                        string[] split = Messages[Messages.Length - 1].Split('.');

                        // STELLE 0: ENCODER-WERT
                        this.EncoderValue = Convert.ToInt32(split[0]);

                        // STELLE 1: BUTTON 1
                        this.Button1 = parseBoolString(split[1]);

                        // LAST UPDATE
                        this.LastUpdate = DateTime.Now;

                        Console.WriteLine("update data");
                        if (this.dataReceived != null && this.connectThreadRunning)
                            this.dataReceived(null, new EventArgs());
                    }
                    catch (Exception exc)
                    {
                        Console.WriteLine("ManualControl:doConnect: " + exc.Message);
                        this.IsConnected = false;
                        //if (this.connectionChanged != null && this.connectThreadRunning)
                        //    this.connectionChanged(this, new EventArgs());
                        continue;
                    }
                }
            }
            Console.WriteLine("doConnect finsihed");
        }

Meine Dispose-Methode sieht so aus:

this.connectThreadRunning = false;
            this.IsConnected = false;
            if (this.connectThread != null)
            {
                //this.udpClient.Close();

                //this.connectThread.Abort();
                this.connectThread.Join();
                this.connectThread = null;
}

Wenn ich nun also das Programm schließe, bleibt die Software aber irgendwo hängen. Die Konsolenaufgabe "doConnect finished" wird ausgeführt, also ist der Thread eigentlich beendet. Aber dennoch bleibt die Dispose-Methode beim Join hängen. Interessanterweise tritt das ganze nur auf, wenn die Verbindung zwischendrin einmal verloren gegangen war und ich mich neu verbunden habe.

Kann mir da jemand helfen?

W
872 Beiträge seit 2005
vor 11 Jahren

Ich habe mich vor einiger Zeit auch mit einem aehnlichen Problem herumgeschlagen, dass ich immer Exceptions bekam beim Beenden des Programmes.
Deine Dispose Methode erzeugt wahrscheinlich einen Deadlock und ist in jedem Fall ohnehin nicht threadsafe.
Das Aufraeumen/Beenden der Threads laeuft automatisch beim Stoppen des Programms.

M
maxwell86 Themenstarter:in
32 Beiträge seit 2010
vor 11 Jahren

Hallo weismat,

vielen Dank für Deine Antwort! Kannst Du mir erklären, warum die Dispose-Methode nicht threadsafe ist? Bzw. kann ich mir das irgendwo durchlesen?

Danke und Grüße,

Max

M
171 Beiträge seit 2012
vor 11 Jahren

Bist Du ganz sicher, dass "doConnect finished" ausgegeben wird, oder siehst Du in der Konsole eine Augabe von einem vorherigen Durchlauf ?

Wenn "doConnect finished" kommt, ist der Thread beendet und Join muss zurück kommen.

Ich vermute, dass Dein Thread irgendwo in einem Receive hängt. Wahrscheinlich läuft beim Reconnect etwas schief, so dass der Timeout nicht gesetzt wird. Wenn in der Zeile


udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 500);

eine Exception geworfen wird, hast Du beispielsweise eine Endlosschleife. Dann steht this.IsConnected auf true, der udpClient wird im Catch geschlossen und beim nächsten Durchlauf kommt er in den else Fall. Dort fliegt eine Exception beim Receive, woraufhin this.IsConnected wieder auf false gesetzt wird usw. Das ist jetzt nur mal auf den ersten Blick ins Blaue getippt, kann auch an anderer Stelle "falsch abbiegen".

Ich würde in jedem Fall mal in die Catches und an den Stellen wo der udpClient geschlossen wird noch jeweils eine Konsolenausgabe einbauen, dann dürftest Du dem Problem vielleicht schon näher kommen.