Laden...

Socket: Als Client verbinden sobald der Host vorhanden ist.

Erstellt von Rubikon vor 13 Jahren Letzter Beitrag vor 13 Jahren 4.368 Views
R
Rubikon Themenstarter:in
7 Beiträge seit 2010
vor 13 Jahren
Socket: Als Client verbinden sobald der Host vorhanden ist.

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.

771 Beiträge seit 2009
vor 13 Jahren

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

R
Rubikon Themenstarter:in
7 Beiträge seit 2010
vor 13 Jahren

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

771 Beiträge seit 2009
vor 13 Jahren

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.

R
Rubikon Themenstarter:in
7 Beiträge seit 2010
vor 13 Jahren

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

699 Beiträge seit 2007
vor 13 Jahren

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.

R
Rubikon Themenstarter:in
7 Beiträge seit 2010
vor 13 Jahren

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

S
72 Beiträge seit 2006
vor 13 Jahren

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.

Siehe TCP/IP Socket-Programmierung in C#

“Ene mene mu und raus bist Du!”

4.221 Beiträge seit 2005
vor 13 Jahren

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

L
667 Beiträge seit 2004
vor 13 Jahren

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