Moin.
Meine WinCE Anwendung soll zu einer Hostanwendung eine Socket Verbindung aufbauen. Meine Anwendung soll als Client fungieren.
Nun kann es aber sein, dass die Hostanwendung später gestartet wird als meine Clientanwendung.
Deshalb habe ich versucht einer Art Pollen zu implementieren:
bool Connected = false;
while(!Connected)
{
try
{
Debug.WriteLine("Connect");
IPEndPoint DestinationEP = new IPEndPoint(IPAddress.Parse("192.168.1.55"), port);
//--- TCP/IP Socket erstellen
Socket ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//--- Zum Remote Endpoint (Server) verbinden
ClientSocket.BeginConnect(DestinationEP, new AsyncCallback(ConnectCallback), ClientSocket);
Connected = true;
}
catch(Exception e)
{
Debug.WriteLine(e.ToString());
Connected = false;
Thread.Sleep(1000);
}
}
Debug.WriteLine("While Schleife verlassen");
Nur da das Fehlschlagen des Verbindens eine Exception auslöst, wird die while Schleife nicht weiter ausgeführt.
Ich weiss auch nicht ob das überhaupt der richtig Ansatz ist. Ich habe mit C# noch sehr wenig Erfahrung.
Denke auch nicht das ich der erste bin der dieses Problem hat. Aber meine Recherche konnte mir leider nicht weiterhelfen.
Generell ist deine Schleife so in Ordnung (da du ja die Exception innerhalb der Schleife verwendest). Da du jedoch eine asynchrone Verbindung einrichtest (mittels BeginConnect), wird diese in einem eigenen Thread durchgeführt (evtl. also besser synchron mittels Connect verbinden?).
Kannst du denn rausfinden, welche Exception geworfen wird und woher (StackTrace)?
Und überprüf mal ob die Callback-Methode 'ConnectCallback' angesprungen wird (durch das asynchrone Connecten dürfest du ja eigentlich erst innerhalb dieser Methode 'Connected = true' setzen).
Die Exception lautet
Eine Ausnahme (erste Chance) des Typs "System.Net.Sockets.SocketException" ist in System.dll aufgetreten.
System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it
...
...
Wenn die erste Zeile sich auf den Rest bezieht, ist das für mich auch plausibel...
(evtl. also besser synchron mittels Connect verbinden?).
Das ist genau das was ich falsch gemacht habe. Vielen Dank 👍
Damit ich auch Connecten/Pollen kann ohne das mein Hauptthread stehen bleibt, erzeuge ich mit in meiner "Socket Engine" einen zweiten Thread in dem ich polle:
class SocketEngine
{
// The port number for the remote device.
private const int port = 6000;
public static void Connect()
{
Thread ConnectThread = new Thread(PollForServer);
ConnectThread.Start();
}
private static void PollForServer()
{
bool Connected = false;
while(!Connected)
{
try
{
Debug.WriteLine("Connect");
IPEndPoint DestinationEP = new IPEndPoint(IPAddress.Parse("192.168.1.55"), port);
//--- TCP/IP Socket erstellen
m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//--- Zum Remote Endpoint (Server) verbinden
//ClientSocket.BeginConnect(DestinationEP, new AsyncCallback(ConnectCallback), ClientSocket);
m_ClientSocket.Connect(DestinationEP);
Connected = true;
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
Connected = false;
Thread.Sleep(5000);
}
}
Debug.WriteLine("Connect Finished");
}
}
Das klappt wunderbar. Nur eine Sache fehlt noch. Wenn die Hostanwendung nun geschlossen wird, müsste der Pollthread wieder gestartet werden.
Es könnte ja sein dass die Hostanwendung zu einem späteren Zeitpunkt wieder gestartet wird. Nur wie mache ich das? Gibt es sowas wie OnClose bei den MFC?
In solch einem Eventhandler könnte ich prima meinen Pollthread wieder starten....
Da die Socket-Klasse keine Ereignisse anbietet, müßtest du entsprechende Exceptions beim Zugriff auf den Socket abfangen (SocketException) und dann dort das Polling wieder aktivieren.
Da die Socket-Klasse keine Ereignisse anbietet, müßtest du entsprechende Exceptions beim Zugriff auf den Socket abfangen (SocketException) und dann dort das Polling wieder aktivieren.
Kannst Du das ein wenig weiter ausführen, wir Du das meinst?
Habe mittlerweile auch die Socket Eigenschaft Connected gefunden. Diese wir allerdings nicht zurück gesetzt wenn meine Hostanwendung geschlossen wird. 🙁
Hier mal mein Vorschlag:
Verwende Timer statt Thread.Sleep().
In dem Timer kannst Du dann einstellen, das er nach X Zeit die Polling-Methode wieder startet. Setze dann den Timer zurück und lege den schlafen.
Wenn dann innerhalb der Methode die SocketException geworfen wird, startest Du den Timer wieder. So kann das Spiel dann die ganze Zeit gehen, bis Du von außen den Timer dauerhaft deaktivierst, oder X-Anzahl falsche Versuche protokolliert hast.
@Stipo: Das ist ein interessanter Ansatz. Vielen Dank für den Tipp.
Allerdings hilft mir das nicht bei dem Problem, dass das Pollen wieder gestartet werden soll, wenn die Hostanwendung geschlossen wird.
Ich habe nämlich noch keine Möglichkeit gefunden, wie mein Programm das mitbekommt, das die Hostanwendung geschlossen wurde... Da ist noch der Haken...
Bin für weitere Tipps dankbar.
Ich habe nämlich noch keine Möglichkeit gefunden, wie mein Programm das mitbekommt, das die Hostanwendung geschlossen wurde... Da ist noch der Haken...
Bin für weitere Tipps dankbar.
Regelmäßig einen Zero-byte Nonblocking Call durchführen.
socket.Send(new byte[1], 0, 0);
Anschließend Exception auffangen.
“Ene mene mu und raus bist Du!”
Ich habe nämlich noch keine Möglichkeit gefunden, wie mein Programm das mitbekommt, das die Hostanwendung geschlossen wurde... Da ist noch der Haken...
Die Kombination aus Socket.Poll und Socket.Available wird dich zu Deinem Ziel führen... habe den Code im Moment nicht greifbar aber ich weiss dass es möglich ist da ich dies selber des öfteren verwendet habe.
[Edit]
Nachtrag: gemeint ist Socket Available (statt wie ursprünglich geschrieben DataAvailable (so heisst die Methode auf dem TcpClient))
Und noch ein Nachtrag: Socket.Poll
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Ich habe nämlich noch keine Möglichkeit gefunden, wie mein Programm das mitbekommt, das die Hostanwendung geschlossen wurde... Da ist noch der Haken...
Es gibt da meines Wissens nach außer über das Abfangen von SocketExceptions, was sehr zeitintensiv und ungenau ist keine praktikable Möglichkeit "mit Bordmitteln".
Ich habe das Problem immer so gelöst, dass ich die Gegenseite (in Deinem Fall die Hostanwendung), in regelmäßigen Abständen eine spezielle Nachricht an den Empfänger (dein Client) schicken lasse. Der Empfänger weiß dann, dass die Gegenseite tot ist, wenn x Sekunden lang keine entsprechende Nachricht mehr angekommen ist. In dem Fall könntest Du also Deine Polling-Loop wieder starten.
"It is not wise to be wise" - Sun Tzu