[SDLNet] Couldn't bind to local port

Simple Directmedia Layer: Portable Spieleprogrammierung
Antworten
nufan
Wiki-Moderator
Beiträge: 2557
Registriert: Sa Jul 05, 2008 3:21 pm

[SDLNet] Couldn't bind to local port

Beitrag von nufan » Sa Sep 12, 2009 8:58 pm

Ich suche jetzt schon seit Stunden nach einem einzigen Fehler in meinem Messenger (der seit gestern ein Qt-GUI hat). Ich weiß genau welche Funktion ihn verursacht, es wird auch eine Fehlermeldung ausgegeben, aber ich komm einfach nicht dahinter wie ich ihn beheben kann. Vielleicht kann mir ja hier jemand weiterhelfen :)
Und zwar bekomme ich beim Versuch mit SDLNet_TCP_Open einen lokalen Server aufzumachen die Fehlermeldung "Couldn't bind to local port". Hier der Konstruktor der Netzwerk-Klasse mit der Methode zur SDL-Initialisierung:

Code: Alles auswählen

Network::Network (Uint16 port)
{

  QString errormsg;                      // string to store an error message

  guiwidget = NULL;                      // there is no GUI yet

  if (StartSDL ())                       // try to initialize SDL and SDLNet
    exit (0);                            // exit if something went wrong

  if ((SDLNet_ResolveHost (&(local.ip), NULL, port)) != 0)      // resolve local host
  {
  
    errormsg = SDLNet_GetError ();       // store the error message
    QMessageBox::critical (guiwidget, "Error",     // show a dialog box containing the error message
                           "Unable to resolve local host:\n" + errormsg, 
                           QMessageBox::Ok);
  
    exit (0);                            // exit the program
  
  }
  
  if ((local.socket = SDLNet_TCP_Open (&(local.ip))) == NULL)  // try to open a local server --> BUG
  {

    errormsg = SDLNet_GetError ();       // store the error message
    QMessageBox::critical (guiwidget, "Error",     // show a dialog box containing the error message
                           "Unable to start local server:\n" + errormsg, 
                           QMessageBox::Ok);

    exit (0);                            // exit the program

  }

  if ((sockets = SDLNet_AllocSocketSet (maxclients)) == NULL)  // try to allocate memory for the sockets
  {

    errormsg = SDLNet_GetError ();       // store the error message
    QMessageBox::critical (guiwidget, "Error",     // show a dialog box containing the error message
                           "Couldn't allocate socket set:\n" + errormsg, 
                           QMessageBox::Ok);

    exit (0);                            // exit the program

  }

  numclients = 0;                        // no clients are connected

  local.name = "Unknown";                // set default name

}



int Network::StartSDL ()
{

  QString errormsg;                                 // string to store error message

  if (SDL_WasInit (SDL_INIT_EVERYTHING) == 0)       // if SDL is not initialized
  {

    if (SDL_Init (SDL_INIT_EVERYTHING) != 0)        // initialize SDL and check for errors
    {

      errormsg = SDLNet_GetError ();                // store the error message
      QMessageBox::critical (guiwidget, "Error",    // show a dialog box containing the error message
                             "Error initializing SDL: \n" + errormsg, 
                             QMessageBox::Ok);

      return 1;                                     // indicating that an error occurred

    }

    atexit (&SDL_Quit);                             // shutdown SDL when the program quits


    if (SDLNet_Init () != 0)                        // initialize SDLNet and check for errors
    {

      errormsg = SDLNet_GetError ();                // store the error message
      QMessageBox::critical (guiwidget, "Error",    // show a dialog box containing the error message
                             "Error initializing SDLNet: \n" + errormsg, 
                             QMessageBox::Ok);

      return 1;                                     // indicating that an error occurred

    }

    atexit (&SDLNet_Quit);                          // shutdown SDLNet when the program quits

  }

  return 0;                                         // indicating that no error occurred

}
An der mit "BUG" kommentierten Stelle wird die Dialog-Box angezeigt und das Programm beendet sich.
Als IP bekomme ich 0, was für eine lokale Verbindung glaube ich stimmt. Der Socket ist aber ebenfalls NULL, was nicht so sein soll. Die SDL-Methode wird durch Vererbung der Klasse mehrfach aufgerufen (unter anderem in einem zweiten Thread), was aber aufgrund des ersten ifs nicht stören sollte. Der zweite Thread lauscht auf Datenpakete, da ich ja sonst nur mit Qt-Slots arbeiten kann. Er ist von QThread abgleitet und ich habe nur "run" überschrieben und Qt-Signale hinzugefügt. Das GUI allein reicht zwar zum Verschicken, aber nicht zum Empfangen.
Ein Neustart hat nix gebracht, Vista zeigt den selben Fehler wie Ubuntu (habs auf zwei verschiedenen Ubuntu-Rechnern probiert) an. Auch der Wechsel der Portnummer bringt nichts.
Ich weiß, dass es vielleicht nicht so eine gute Idee ist SDLNet mit Qt zu verwenden, da ja Qt selbst auch Klassen für Netzwerkprogrammierung bereitstellt, aber ich verstehe trotzdem nicht warum das nicht funktioniert.

Ich bin jetzt echt ratlos...

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: [SDLNet] Couldn't bind to local port

Beitrag von fat-lobyte » Sa Sep 12, 2009 10:22 pm

nufan hat geschrieben:Und zwar bekomme ich beim Versuch mit SDLNet_TCP_Open einen lokalen Server aufzumachen die Fehlermeldung "Couldn't bind to local port".
Tolle fehlermeldung von der SDL. :-/ Geht so in richtung "geht nicht".
Versuch mal nach der Zeile einen perror() Aufruf zu setzen. Die gibt unter Linux meist gute Infos über das Problem und wenn du glück hast wird die errno noch vom letzten Systemaufruf der SDL sein.
Auch der Wechsel der Portnummer bringt nichts.
Dann nehme ich an, du hast schon versucht einen Port außerhalb der 1024 zu suchen... Das wäre nämlich mein erster Gedanke gewesen (man darf ja unter Unix die Well-Known-Ports nur als root benutzen)

Wie wird eigentlich (local.ip) initialisiert? Hast du da alles richtig gemacht?
Die SDL-Methode wird durch Vererbung der Klasse mehrfach aufgerufen (unter anderem in einem zweiten Thread), was aber aufgrund des ersten ifs nicht stören sollte. Der zweite Thread lauscht auf Datenpakete, da ich ja sonst nur mit Qt-Slots arbeiten kann
Hab ich das richtig verstanden, du benutzt TCP für die Inter-Thread kommunikation?
Ich weiß, dass es vielleicht nicht so eine gute Idee ist SDLNet mit Qt zu verwenden, da ja Qt selbst auch Klassen für Netzwerkprogrammierung bereitstellt, aber ich verstehe trotzdem nicht warum das nicht funktioniert.
Denke nicht dass das Probleme machen sollte... Allerdings versuch mal Qt ohne Netzwerk zu kompilieren, das geht sicher irgendwie (wenn das pakete deiner distro sind wirst du sie vielleicht auch irgendwie deinstallieren können).
Hast du übrigens die Qt Netzwerklibrary schon ausprobiert? Vielleicht gefällt dir die ja besser als SDLNet...

mfg, fat-lobyte

ps.: Hast du den Code Teilweise unter Windows geschrieben und sind jetzt die Zeilenenden gemischt, oder stehst du einfach auf Leere Zeilen zwischen dem Code ;-)
Haters gonna hate, potatoes gonna potate.

nufan
Wiki-Moderator
Beiträge: 2557
Registriert: Sa Jul 05, 2008 3:21 pm

Re: [SDLNet] Couldn't bind to local port

Beitrag von nufan » Sa Sep 12, 2009 10:39 pm

fat-lobyte hat geschrieben:
nufan hat geschrieben:Und zwar bekomme ich beim Versuch mit SDLNet_TCP_Open einen lokalen Server aufzumachen die Fehlermeldung "Couldn't bind to local port".
Tolle fehlermeldung von der SDL. :-/ Geht so in richtung "geht nicht".
Versuch mal nach der Zeile einen perror() Aufruf zu setzen. Die gibt unter Linux meist gute Infos über das Problem und wenn du glück hast wird die errno noch vom letzten Systemaufruf der SDL sein.
"Address already in use"
Ich glaube ich kenne jetzt den Fehler... Bei der Netzwerkklasse hab ich bei der Vererbung zwei entscheidende Fehler gemacht.
1. In der Klasse speichere ich unter anderem die IPs der Clienten, wenn ich die an zwei Klassen vererbe, sind das aber nicht die gleichen. Ein schwerer Fehler, aber nicht der Grund für die Fehlermeldung.
2. Wenn der Konstruktor öfters aufgerufen wird, versucht SDL den Port neu zu belegen, was anscheinend auch der Grund für die Fehlermeldung ist.
Danke für den Hinweis. Da muss ich noch mal ran... hab versucht das C++-mäßig aufzuziehen, ging aber daneben.
Habs jetzt vorerst mit einem Pointer auf den Netzwerk-Teil der anderen Klassen als Parameter für den Konstruktor des Threads gelöst, ich sollte aber mein ganzes Klassenkonzept noch einmal überdenken. Und außerdem prüfen ob perror() immer sinnvollere Fehlermeldungen als SDL ausgibt.
fat-lobyte hat geschrieben:Wie wird eigentlich (local.ip) initialisiert? Hast du da alles richtig gemacht?
Beim Aufruf von SDLNet_ResolveHost wird ein Zeiger darauf übergeben und die Struktur wird mit Infos gefüllt.
fat-lobyte hat geschrieben:Hab ich das richtig verstanden, du benutzt TCP für die Inter-Thread kommunikation?
Zwischen Clienten verwende ich TCP. Für die Kommunikation innerhalb der Threads verwende ich Qt-Signale/Slots. Löst der Listen-Thread ein Signal aus, wird im GUI-Thread der entsprechende Slot ausgelöst.
Beispiel: Listen empfängt eine Nachricht und übergibt den QString mittels Signal an den Slot des Text-Widgets weiter, wo es an den gesamten Text angefügt wird.
fat-lobyte hat geschrieben:Denke nicht dass das Probleme machen sollte... Allerdings versuch mal Qt ohne Netzwerk zu kompilieren, das geht sicher irgendwie (wenn das pakete deiner distro sind wirst du sie vielleicht auch irgendwie deinstallieren können).
Hast du übrigens die Qt Netzwerklibrary schon ausprobiert? Vielleicht gefällt dir die ja besser als SDLNet...
Man muss im Qt-Project-File extra

Code: Alles auswählen

QT += network
angeben, damit die Netzwerk-Klassen zur Verfügung stehen. Hab mir die Klassen mal angeschaut, die sind deutlich komplexer als SDLNet, man kann damit aber auch mehr machen (z.B. Proxy).
fat-lobyte hat geschrieben:ps.: Hast du den Code Teilweise unter Windows geschrieben und sind jetzt die Zeilenenden gemischt, oder stehst du einfach auf Leere Zeilen zwischen dem Code ;-)
Ich lass gerne viel Abstand, finde es so übersichtlicher :)

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: [SDLNet] Couldn't bind to local port

Beitrag von fat-lobyte » So Sep 13, 2009 11:22 am

Überdenken ist immer gut ;-)

Abe "Address allready in use" kann auch von was anderem kommen. Wenn dein Programm sich beendet und den socket schließt bleibt der Socket oft "im System hängen", und wird erst später aufgeräumt. Wenn du beim nächsten Aufruf den Port wiederverwenden willst, musst du dem Socket die option "SO_REUSEADDR" setzen. Wie das mit SDLNet geht weiß ich nicht, unter Unix würdest du sie mit setsockopt() setzen.
Haters gonna hate, potatoes gonna potate.

nufan
Wiki-Moderator
Beiträge: 2557
Registriert: Sa Jul 05, 2008 3:21 pm

Re: [SDLNet] Couldn't bind to local port

Beitrag von nufan » So Sep 13, 2009 11:29 am

fat-lobyte hat geschrieben:Abe "Address allready in use" kann auch von was anderem kommen. Wenn dein Programm sich beendet und den socket schließt bleibt der Socket oft "im System hängen", und wird erst später aufgeräumt.
Hatte das Problem wenn ich das Programm mit Strg+Z killen musste. Dann musste zusätzlich der Prozess im gnome-system-monitor beendet werden. Aber ich habe ja verschiedene Rechner und Betriebssysteme verwendet und mehrere Male neu gestartet, also fiel das für mich als Grund weg.
fat-lobyte hat geschrieben:Wenn du beim nächsten Aufruf den Port wiederverwenden willst, musst du dem Socket die option "SO_REUSEADDR" setzen. Wie das mit SDLNet geht weiß ich nicht, unter Unix würdest du sie mit setsockopt() setzen.
Das gibts laut Referenz bei SDLNet nicht.

Antworten