Probleme mit ServerSocket->Socket->Disconnect(i)



  • Hallo, ich versuche mich gerade etwas mit Netzwerkkommunikation über Sockets anzufreunden, um eigentlixch ein einfaches Chatprogramm zu schreiben.

    Dabei verbinden sich beliebig viele Clients mit dem Server, dieser speichert in einer Map den übermittelten Username als Schlüssel und die Ip, bzw. den Username und die Verbindungsnummer aus dem Feld

    ServerSocket->Socket->Connections[i]
    

    Ferner sendet der Server den Clients die anderen Nutzernamen (also von den restlichen Clients) und verteilt die Nachrichten von den Clients ggf. weiter an die restlichen Sockets.

    So weit so gut.

    Alledings wollte ich verhindern, daß mehere Nutzer den gleichen Nutzernamen (Username) besitzen, deshalb wird im folgenden Ereignis geguckt, ob der Nutzername bereits auftritt und wenn dem so ist wird mit

    ServerSocket->Socket->Disconnect(i)
    

    diese Verbindung wieder verbinden.
    So ist zumindest die Idee, allerdings wird nicht nur der gewünschte Client disconnected sondern auch alle anderen, bei allen Clients wird das Ereignis

    ClientSocketDisconnect
    

    aufgerufen.
    Dabei dachte ich, ich kann mit

    Disconnect(i)
    

    nur zu dem entsprechenden Client die Verbindung trennen.

    Wenn jemand eine Idee hat oder mir irgendwie weiterhelfen könnte wär das ganz nett 🤡

    Hier ist mal das ganze Ereignis:

    void __fastcall TForm1::ServerSocketClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
      AnsiString nachricht=Socket->ReceiveText();
      bool ausgeben=true;
      if (nachricht.Length()>=4)
      {
            AnsiString befehl=nachricht.SubString(1,4);
            if (befehl=="§USN") // Username
            {
              ausgeben=false;
              //Zur Kontrolle, ob der Name bereits verwendet wird.
              bool vorhanden=false;
              if (nachricht.SubString(5,nachricht.Length()-4)!=getUserName())
              {
                std::map<AnsiString,AnsiString>::iterator iter2=VerbindungenIp.begin();
                while ((iter2!=VerbindungenIp.end())&&(vorhanden==false))
                {
                  if (iter2->first==nachricht.SubString(5,nachricht.Length()-4))
                  {
                     vorhanden=true;
                  }
                  iter2++;
                }
              }
              else
              {
                vorhanden=true;
              }
    
              // Speichern des Nutzernamens und weitersenden an die Clients
    
              int i=0;
              while (ServerSocket->Socket->Connections[i]->RemoteAddress!=Socket->RemoteAddress)
              {
                i++;
              }
              if (vorhanden==false)
              {
                ComboBox1->Items->Add(nachricht.SubString(5,nachricht.Length()-4));
                setVerbindungN(nachricht.SubString(5,nachricht.Length()-4),i);
                setVerbindungIp(nachricht.SubString(5,nachricht.Length()-4),ServerSocket->Socket->Connections[i]->RemoteAddress);
    
                int j=0;
                while (j<ServerSocket->Socket->ActiveConnections)
                {
                  if (j!=i)
                  {
                    ServerSocket->Socket->Connections[j]->SendText("§USN"
                    + nachricht.SubString(5,nachricht.Length()-4));
                  }
                  j++;
                }
                std::map<AnsiString,int>::iterator iter3=VerbindungenN.begin();
                while (iter3!=VerbindungenN.end())
                {
                  if (iter3->second!=i)
                  {
                    ServerSocket->Socket->Connections[i]->SendText("§USN"
                    + iter3->first);
                  }
                  iter3++;
                }
              }
              else   // Um mehrdeutige Nutzernamen zu verhindern
              {
                ServerSocket->Socket->Connections[i]->SendText("Ihr Benutzername wird bereits verwendet.");
    
    //  :arrow_right: SO HIER SOLLTE MEIN PROBLEM LIEGEN:
    
                ServerSocket->Socket->Disconnect(i);            
              }
    
            }
            else if (befehl=="§STU")    // Send to user
            {
            // Weiter senden an
            // §STUALLNachricht oder §STUNUTZERNAME§Nachricht in der Nachricht ist bereits der ursprüngliche Nutzername vorangestellt
    
              AnsiString adressat=nachricht.SubString(5,3);
              if (adressat=="ALL")
              {
                std::map<AnsiString,int>::iterator iter=VerbindungenN.begin();
                while (iter!=VerbindungenN.end())
                {
                  if (VerbindungenIp[iter->first]!=Socket->RemoteAddress)
                  {
                    ServerSocket->Socket->Connections[iter->second]->SendText(nachricht.SubString(8,nachricht.Length()-7));
                  }
                  iter++;
                }
                nachricht=nachricht.SubString(8,nachricht.Length()-7);
              }
              else
              {
                int i=6;
                adressat=nachricht.SubString(5,1);
                befehl=nachricht.SubString(i,1);  // die Variable befehl wird nun als einzelnes Zeichen verwendet!
                for (i=7;(i<nachricht.Length())&&(befehl!="§");i++)
                {
                  adressat=adressat+befehl;
                  befehl=nachricht.SubString(i,1);
                }
                if (adressat!=getUserName())
                {
                  ServerSocket->Socket->Connections[VerbindungenN[adressat]]->SendText(nachricht.SubString(i,nachricht.Length()-i+1));
                }
                nachricht=nachricht.SubString(i,nachricht.Length()-i+1);
              }
            }
      }
      if (ausgeben==true)
      {RichEdit1->Lines->Add(nachricht);}
    
      DebugenAusgabe(); // Säter löschen
    
    }
    


  • ServerSocket->Socket->Connections[i]->Disconnect();
    

    Sollte dein Problem lösen. Über deinen Code wird die Verbindung vom Server für *alle* beendet, auch die eigene.



  • Das hatte ich auch schon versucht, leider kommt bei

    ServerSocket->Socket->Connections[i]->Disconnect();
    

    Folgende Compilerfehlermeldungen:

    [C++ Error] Dsa1.cpp(345): E2193 Too few parameters in call to '_fastcall TCustomWinSocket::Disconnect(int)'
    [C++ Error] Dsa1.cpp(360): E2096 Illegal structure operation

    Anscheindend muß immernoch ein Parameter vom Typ int übergeben werden

    ServerSocket->Socket->Connections[i]->Disconnect(i);
    

    das macht allerdnings nicht wirklich Sinn, es wird zwar vom Compiler abzeptiert, allerdings zeigt es auch überhaupt keine Wirkung im Programm.
    :o(



  • Ich hab das so gelöst das wenn sich jemand anmeldet, dessen Nick aber schon vergeben ist, der Server einen Nachricht schickt von wegen ###ClientDisconnect#. Wenn der Client dies erhält führt er "ClientSocket1->Close();" aus und in seinem Event bei Disconnect startet er dann z.B. das Formular um sich neu anzumelden bzw. eines wo er seinen Nick neu eingeben muss.



  • void __fastcall TForm1::ServerSocketClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
        ServerSocket1->Socket->Connections[i]->Disconnect(Socket->SocketHandle);
    }
    

    So sollte es aussehen und funktionieren. Das hättest du aber mit lesen in der Hilfe und ein bischen Nachdenken schon selber geschaft 😉



  • Dann erstmal danke, werd morgen mal ausprobieren, wäre abersicher erstmal nicht darauf gekommen ,da icvh mit handles nicht so auskenne, hab dazu nur mal ein kleines Kapitel gelesen.



  • Du solltest vom Gedanken "oh, da kennich mich nicht aus, das schnall ich eh nicht" zum Gedanken "oh, da kenn ich mich noch nicht aus. Lesen wir trotzdem mal ein bischen drüber" wechseln. Wenn dieser Schritt vollzogen ist, dann kriegt man sowas mit HIlfetexten auch raus (o;

    -junix


Anmelden zum Antworten