Server suchen



  • Hi Leutz!

    Hier mal wieder eine Frage zum Thema: Einen Server im LAN suchen mit TServerSocket/TClientSocket 🙂

    Ich habe einen Chat geschrieben (für mich und meine Arbeitskollegen :D). Nun möchte ich aber von dem umständlichen Weg, die IP-Adresse des Servers über eine Datei auf einem zentralen Netzlaufwerk zu übergeben, weg und stattdessen den Server suchen lassen. Tja und hieran beiße ich mir seit ein paar Tagen die Zähne aus.

    Hier mal einen meiner zahllosen Ansätze.

    Client = TClientSocket
    IPList = ListBox in denen die IP-Adressen enthalten sind, die befragt werden sollen

    for(int i = 0; i<IPList->Items->Count; ++i)
    {
       Client->Address = IPList->Items->Strings[i];
       Client->Active  = true;
    
       if(!Client->Socket->Connected)
       {
          Client->Active  = false;
          ChatBox->Lines->Add("Keinen Server gefunden!");
       }
    }
    

    Die Sache ist nun folgende. Da das ganze in der for-Schleife viel zu schnell durchlaufen wird und der ClientSocket so schnell nicht reagieren kann, (so ein Verbindungsaufbau dauert ja immer ein bischen) brauche ich irgendeine andere Metode, um nach einem Server zu suchen. Ich habe auch schon ein bischen im I-Net gesucht, bin aber noch nicht auf etwas Brauchbares gestoßen.

    Vielleicht habt ihr ja mehr Ideen und wisst wie ich das realisieren könnte.



  • mit sleep()



  • Aber mit Sleep() halte ich doch das komplette Programm für die angegebene Zeit an und das war eigentlich nicht das was ich wollte. Irgendwelche anderen Vorschläge?



  • Du denkst falsch: Du kannst hier nicht eine Schleife mit While oder so implementieren.. du musst indirekt eine Schleife über die verschiedenen Events bauen... Haken: Du kommst nicht mit einem einzelnen Socket aus. Du musst 2 Sockets haben und die abwechslungsweise aktiv schalten... (sofern ich mich richtig entsinne)

    -junix



  • nehm doch einfach nen Timer, und beweg dich in der Liste nach dem Intervall entweder ein Item vorwärts, oder nehm immer das erste und lösch die vorausgehenden. Du müsstest den Timeout des sockets natürlich mit der Timerzeit gleichsetzen.



  • junix schrieb:

    du musst indirekt eine Schleife über die verschiedenen Events bauen... Haken: Du kommst nicht mit einem einzelnen Socket aus. Du musst 2 Sockets haben und die abwechslungsweise aktiv schalten... (sofern ich mich richtig entsinne)

    Achso. Ich werds mal testen und ausarbeiten. Melde mich dann bei weiteren Denkschluchten 🙂



  • peaceohm schrieb:

    Du müsstest den Timeout des sockets natürlich mit der Timerzeit gleichsetzen.

    Nö. Kannst auch einfach den Timer beim Timeout auf aktiv schalten... stimmt so ginge es mit 1 Socket und 1 Timer... allerdings war ich noch nie fan von Timing-Geschichten... das fabriziert immer so blöde Nebeneffekte die man nicht vorhersehen kann...

    -junix



  • Ich habs jetzt umgesetzt und zwar folgendermaßen:
    Ich habe auf meiner Form jetzt 2 TClientSocket-Objekte. (Client und Client2). Ich habe über das OnError-Event dann eine Schleife erstellt um die verschiedenen Adressen zu überprüfen. Das funktioniert wunderbar. Allerdings lässt sich "Client" beim 2. Mal nutzen nicht mehr starten, obwohl ich explizit

    Client->Active = true;
    

    sage. Ich setzte im OnShow-Event der Form das erste Mal Client->Active = true;

    Hier mal mein Code

    //Ein Verbindungsaufbau ist fehlgeschlagen bei Client
    void __fastcall TfrmMC::ClientError(TObject *Sender,
          TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
        switch(ErrorEvent)
        {
            case eeConnect:
            {
                FormSupply->setConnectFlag(false);
                //Client2 aktiv schalten und Client1 abschalten
                Client->Active = false;
                ChatBox->Lines->Add(Client->Address + " <= Keinen Server gefunden!");
                if(FormSupply->getAnz() < IPList->Items->Count)
                {
                    FormSupply->setAnz(1);
                    Client2->Address = IPList->Items->Strings[2];
                    Client2->Active = true; //<-- Hier schalte ich auf true, lt. Debugger bleibt es aber false! :confused:
                    break;
                }
                //Alle IP-Adressen durchlaufen
                else
                {
                    ChatBox->Lines->Add("Keinen Server gefunden!");
                    break;
                }
            }
        }
       ErrorCode = 0;
    }
    //---------------------------------------------------------------------------
    //Ein Verbindungsaufbau ist fehlgeschlagen bei Client2
    void __fastcall TfrmMC::Client2Error(TObject *Sender,
          TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
        switch(ErrorEvent)
        {
            case eeConnect:
            {
                FormSupply->setConnectFlag(false);
                //Client2 aktiv schalten und Client1 abschalten
                Client2->Active = false;
                ChatBox->Lines->Add(Client2->Address + " <= Keinen Server gefunden!");
                if(FormSupply->getAnz() < IPList->Items->Count)
                {
                    FormSupply->setAnz(1);
                    Client->Address = IPList->Items->Strings[2];
                    Client->Active = true; //<-- Hier schalte ich auf true, lt. Debugger bleibt es aber false! :confused:
                    break;
                }
                //Alle IP-Adressen durchlaufen
                else
                {
                    ChatBox->Lines->Add("Keinen Server gefunden!");
                    break;
                }
            }
        }
        Client->Active = true;
        ErrorCode = 0;
    }
    

    Noch als Hinweis, ich gebe hier mit Absicht feste Werte bei der IPList an, da ich es erst mal nur mit IP-Adressen teste.



  • üblicherweise verwendet man aber auch die Funktionen Connect und Disconnect und vergewaltigt nicht das Active-Flag (o;

    Evtl hilft das weiter...

    -junix



  • Ich bekomms nicht hin. Ich hab jetzt Open, Open(mit Parameter), Close getestet. Bei (Dis)Connect(int Socket) findet er immer einen Server, was aber nicht sein kann. Evtl nutze ich diese Methode auch falsch?!

    Bei Open()/Close() passiert das gleiche wie oben schon beschrieben. 😞



  • Nach längerem hin-undher ab ich jetzt festgestellt, das es an der ListBox liegt. Ich kann nicht auf den 3. (und auch letzten) Eintrag zugreifen. Leider verstehe ich nicht was ich da viel falsch machen kann. Ich fange bei 0 an und gehe bis ListBox->Items->Count-1. Danke nochmal für eure Hilfe.

    @junix
    Ich hab das ganze jetzt so umgebaut, das man nur noch einen Client benötigt um einen Server zu suchen 🙂
    Hier mal eine Version die nicht auf meine Verhältnisse zugeschnitten, sondern etwas allgemeiner gefasst ist.

    Benötigt wird:

    TClientSocket *ClientSocket1;
    TRichEdit *RichEdit1; //Dient zur Ausgabe
    TListBox *ListBox1; //Hier müssen alle IP-Adressen eingetragen werden
    int verlauf; //dient zum Zählen
    

    hier der Code im OnError-Event von ClientSocket1

    void __fastcall TForm1::ClientSocket1Error(TObject *Sender,
          TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
        switch(ErrorEvent)
        {
            case eeConnect: //siehe Hilfe zu TErrorEvent
            {
                //Client abschalten, neue IP setzten und wieder aktiv schalten
                ClientSocket1->Close();
                RichEdit1->Lines->Add(ClientSocket1->Address + " <= Keinen Server gefunden!");
                verlauf++;
                if(FormSupply->getAnz() < ListBox1->Items->Count)
                {
                    ClientSocket1->Address = ListBox1->Items->Strings[verlauf];
                    ClientSocket1->Open();
                    break;
                }
                else
                {
                    RichEdit1->Lines->Add("Keinen Server gefunden!");
                    break;
                }
            }
        }
        ErrorCode = 0; //damit keine Exception geworfen wird
    }
    


  • Hmmm sieht nett aus. Tu mir nen Gefallen und schau mal auf den Calling-Stack ob sich da was aufschaukelt oder ob nach dem Aufruf von Open() der Error-event-handler schön beendet wird, ja?

    -junix



  • Beim durchsteppen mit dem Debugger und Überwachung des Stacks hab ich keine Probleme festgestellt. Die Methode wird korrekt beendet und der Stack bleibt in konstanter Größe 🙂



  • Great... (o:



  • PuppetMaster2k schrieb:

    Ich bekomms nicht hin. Ich hab jetzt Open, Open(mit Parameter), Close getestet. Bei (Dis)Connect(int Socket) findet er immer einen Server, was aber nicht sein kann. Evtl nutze ich diese Methode auch falsch?!

    Bei Open()/Close() passiert das gleiche wie oben schon beschrieben. 😞

    mich würde mal interessieren ob du inzwischen eine antowrt auf dieses problem gefunden hast... ?

    ich hab nämlich grad mit einem ähnlichen problem zu kämpfen und meine lösung funktioniert zwar ist aber ein wenig verquer...



  • Ich hab das damals anders gemacht.
    Ich hab ne UDP komponete genommen und ein Broadcast gesendet. an einen bestimmten Port. Die Server die auf dem Port lauschen, habe entsprechend geantwortet.
    Und der Client hat das passend ausgewertet.

    War für mich einfacher.


Anmelden zum Antworten