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?
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.
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
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.