PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Nach Servern im lokalen Netzwerk suchen



TheNewNewUser
22-09-2004, 18:00
Hi!

Ich schreib grad ein kleines SDL-Spiel mit Netzwerkspielfunktion(durch Socketproging). Allerdings gibts da noch ein Problem.
Wenn man an einem Spiel teilnimmt muss man die IP-Adresse des Servers kennen.

Wie bekomme ich das hin, dass ich alle verfügbaren Spiele im Netzerk anzeigen lasse? :confused:

PS: Das Spiel verwendet als Serverport 1158.

fs111
22-09-2004, 19:01
Du könntest eine zentrale Einheit schaffen, an der sich alle Spielserver mit ihren speilen anmelden müssen, über die dei Benutzer die Spiele dann finden.

fs111

Deever
22-09-2004, 20:54
Gute Frage! Wie machen das eigentlich die "Netzwerkspiele"? Per Broadcast?

Gruß,
/dev

SeeksTheMoon
22-09-2004, 21:02
Am billigsten ist ein UDP-Broadcast des Clients und wenn der Server das Paket empfängt kann (muss!) er sofort eine Antwort schicken und damit hast Du Deinen Spiel-Server.

TheNewNewUser
24-09-2004, 07:36
Am billigsten ist ein UDP-Broadcast des Clients und wenn der Server das Paket empfängt kann (muss!) er sofort eine Antwort schicken und damit hast Du Deinen Spiel-Server.

Und wie mach ich sowas? :confused:

TheNewNewUser
25-09-2004, 05:30
So ich hab jetz was geschrieben:

Hier die client.c


#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

int main (void)
{
int s;

s = socket (AF_INET, SOCK_DGRAM, 0);

if (s != -1)
{

struct sockaddr_in addr;

addr.sin_addr.s_addr = inet_addr ("192.168.0.255");
addr.sin_port = htons(1158);
addr.sin_family = AF_INET;

char optval = 1;

socklen_t optsize = sizeof(&optval);

setsockopt (s, SOL_SOCKET, SO_BROADCAST, (char *) &optval, optsize);
setsockopt (s, SOL_SOCKET, SO_DONTROUTE, (char *) &optval, optsize);

/*if (connect(s, (struct sockaddr*) &addr, sizeof(addr)) == -1)
{
printf ("connect() failed\n");
return 2;
}
else
{*/
char buffer[1024];

if (sendto (s, buffer, 1, MSG_DONTROUTE, (struct sockaddr*) &addr, sizeof(addr)) != -1)
{
printf ("gesendet!\n");

struct sockaddr_in cli;
socklen_t cli_size;

while (recvfrom(s, buffer, sizeof(buffer)-1, 0, (struct sockaddr*) &cli, &cli_size) != -1)
{
printf ("antwort ist da von %s\n", inet_ntoa(cli.sin_addr));
}
}
else
{
perror ("sendto() failed");
return 2;
}
//}
}
else
{
printf ("socket() failed\n");
return 1;
}

close (s);

return 0;
}


server.c:


#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main (void)
{
int s;

s = socket (AF_INET, SOCK_DGRAM, 0);

if (s != -1)
{

struct sockaddr_in addr;

addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(1158);
addr.sin_family = AF_INET;

if (bind(s, (struct sockaddr*) &addr, sizeof(addr)) == -1)
{
printf ("connect() failed\n");
return 2;
}
else
{
char buffer[1024];

struct sockaddr_in cli;
socklen_t cli_size;

cli_size = sizeof(cli);

if (recvfrom(s, buffer, sizeof(buffer)-1, 0, (struct sockaddr*) &cli, &cli_size) != -1)
{
printf ("empfangen!\n");
sendto (s, buffer, 1, 0, (struct sockaddr*) &cli, cli_size);
}
}
}
else
{
printf ("socket() failed\n");
return 1;
}

close (s);

return 0;
}


Derzeitiges Probleme:
1. Nicht alle netzwerke haben den Broadcast 192.168.0.255. Wie kann ich diesen unter Linux (als normaler User) und unter Windows ermitteln.
2. Wenn man den Server auf dem selben Rechner ausführt heißt es



...
antwort ist da von 0.0.0.0


Wieso denn 0.0.0.0?

Kann mir da jemand helfen? :confused:

locus vivendi
25-09-2004, 07:50
Ob das dein zweites Problem zuverlässig behebt kann ich nicht sagen, aber du hast mit Sicherheit noch einen Fehler drin. In dem Aufruf von socket übergibst du "AF_INET", also ein "Address Format". Aber das ist nicht richtig. socket erwartet als argument einen "Namespace", wie mir ein kurzer Blick in die Doku sagt... Der Namespace der zum Address Format AF_INET korrespondiert ist "PF_INET". Versuchs mal damit.

panzi
25-09-2004, 09:53
Ob das dein zweites Problem zuverlässig behebt kann ich nicht sagen, aber du hast mit Sicherheit noch einen Fehler drin. In dem Aufruf von socket übergibst du "AF_INET", also ein "Address Format". Aber das ist nicht richtig. socket erwartet als argument einen "Namespace", wie mir ein kurzer Blick in die Doku sagt... Der Namespace der zum Address Format AF_INET korrespondiert ist "PF_INET". Versuchs mal damit.
Wobei aber AF_INET und PF_INET den selben wert haben, ABER das schreibt der Standard nicht vor, könnte also bei manchen Betriebssystemen/clibs anders sein.

locus vivendi
25-09-2004, 10:29
Ich sehe noch etwas, in diesem Fragment:


struct sockaddr_in cli;
socklen_t cli_size;

while (recvfrom(s, buffer, sizeof(buffer)-1, 0, (struct sockaddr*) &cli, &cli_size) != -1)
{
printf ("antwort ist da von %s\n", inet_ntoa(cli.sin_addr));
}


Du hast cli_size nicht initalisiert. Du solltest dir vielleicht noch einmal die Dokumentation zu allen Systemaufrufen durchlesen die du verwendest, das ist nämlich zuverlässiger als sich darauf zu verlassen, das es Andere aus irgendeinem Forum tun oder getan haben...

Deever
25-09-2004, 11:02
Wegen dem "0.0.0.0": Wenn du willst, daß dein Client eine bestimmte Adresse benutzt, mußt du ihn ebenfalls bind()en.

HTH!
/dev

TheNewNewUser
25-09-2004, 12:47
Wegen dem "0.0.0.0": Wenn du willst, daß dein Client eine bestimmte Adresse benutzt, mußt du ihn ebenfalls bind()en.

HTH!
/dev

Das "0.0.0.0" ist deshalb weil ich cli_size nicht initialisiert habe. Das hab ich heut morgen kurz nach dem abschicken gemerkt.

Also Problem 2 ist gelöst.

Ich hab noch was in den manual-pages gefunden:



addr.sin_addr.s_addr = INADDR_BROADCAST;


Laut manual-pages soll dann an alle lokalen Rechner was gesendet werden.
Allerdings gibts dann bei sendto() den Fehler "Network unreachable"

Weiß jemand, was da schief geht oder kann mir sagen, wie ich die Broadcast adresse ermittle?

SeeksTheMoon
25-09-2004, 15:35
ich weiß nicht ob Du unbedingt diese Lib benutzen musst, ich kann Dir sehr ptypes empfehlen:
http://www.melikyan.com/ptypes/doc/index.html

Hier steht z.B. wie man einen UDP-Broadcast ganz einfach macht: http://www.melikyan.com/ptypes/doc/inet.ipmessage.html


ipmessage::ipmessage(ipaddress ip, int port) constructs an ipmessage object and assigns the peer ip/port values. To send a broadcast message to all hosts on a local network, assign a predefined constant ipbcast to ip.

Socket-Proggen ist ansonsten relativ unangenehm, das wird hier alles schön vereinfacht und ist ebenfalls plattformunabhängig.

TheNewNewUser
25-09-2004, 16:12
ich weiß nicht ob Du unbedingt diese Lib benutzen musst, ich kann Dir sehr ptypes empfehlen:
http://www.melikyan.com/ptypes/doc/index.html

Hier steht z.B. wie man einen UDP-Broadcast ganz einfach macht: http://www.melikyan.com/ptypes/doc/inet.ipmessage.html



Socket-Proggen ist ansonsten relativ unangenehm, das wird hier alles schön vereinfacht und ist ebenfalls plattformunabhängig.

Ich hab jetzt eben schon mein ganzes Spiel in sockets geschrieben und bin sehr glücklich damit.
Wenns auch "unangenehm" ist.

Zu meinem Problem:

INADDR_BROADCAST ist nur ne konstante mit der bedeutung "255.255.255.255".

Und bei nem sendto() nach "255.255.255.255" kommt "Network unreachable". Aber nur unter Linux. Unter Windoof klappts.

Der Pingbefehl geht auch mit broadcast z.B:



ping -b 192.168.0.255

64 Bytes from 192.168.0.xx ...


Und mit dem Ping klappt auch das unter Linux:



ping -b 255.255.255.255

64 Bytes from 192.168.0.xx ...


Also muss ich jetzt folgendes machen:

Entweder:

Die Broadcast eines netzes ermitteln (z.B: "192.168.0.255")

oder:

Dafür sorgen dass bei einem sendto() an "255.255.255.255" kein "Network unreachable" mehr kommt. Möglich ists: Es klappt unter Windoof mit meinem Prog und unter Linux mit ping -b.

Weiß jemand über eine dieser Möglichkeiten bescheid?

TheNewNewUser
26-09-2004, 04:32
Hi! Ich hab das Problem gelöst.

Das da musste weg:



setsockopt (s, SOL_SOCKET, SO_DONTROUTE, (char *) &optval, optsize);


Dann hats auch unter Linux mit INADDR_BROADCAST geklappt.