C++: Problem mit bind()
Klaus Kleenfelden
- programmiertechnik
Grüß Gott werte Gemeindemitglieder,
Also ich habe ein etwas größeres Projekt und ich bin unter anderem auch für den Netzwerkteil mitverantwortlich(bin darin aber kein Experte :(). Deshalb poste ich ja hier weil ich ein Problem habe und ich nicht weiss wie man es löst. Langer Rede kurzer Sinn, erstmal der Code der den Fehler verursacht:
// Das ist der Beginn einer Funktion die als Thread von pthread_create aufgerufen wird.
// Das Programm an sich _muss_ von root gestartet werden. Gibt auch einen Test dafür im Programm.
int soc, soc_cli;
int y = 1;
socklen_t cli_len;
struct sockaddr_in6 srv_addr, cli_addr;
soc = socket(AF_INET6, SOCK_STREAM, 0);
if(soc == -1) {
cerr << "couldn't create socket. socket(); ";
perror(NULL);
exit(EXIT_FAILURE);
}
srv_addr.sin6_family = AF_INET6;
srv_addr.sin6_port = htons(HTTP_PORT);
setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y));
y = 512;
setsockopt(soc, SOL_SOCKET, SO_SNDBUF, &y, sizeof(y));
y = 255;
setsockopt(soc, SOL_SOCKET, SO_RCVBUF, &y, sizeof(y));
if(bind(soc, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) != 0) {
cerr << "Error: binding server socket. bind(); ";
perror(NULL);
exit(EXIT_FAILURE);
}
if(listen(soc, 8) != 0) {
cerr << "Error: listening server socket. listen(); ";
perror(NULL);
exit(EXIT_FAILURE);
}
// hier käme dann noch der accept()-Teil
Die Fehlermeldung lautet:
"Error: binding server socket bind(); Cannot assign requested address"
Und wird wie man sieht, von bind() verursacht. Was ist falsch?
Als letztes habe ich den Code von IPv4 auf IPv6 umgerüstet. Bis dahin lief der Code einwandfrei. Habe ich was übersehen, was falsch gemacht?
Zu der Meldung findet man auch nicht besonders viel Hilfreiches mit Google.
Auf Wiedersehen und Viele Grüße
Klaus Kleenfelden
Hallo Klaus,
"Error: binding server socket bind(); Cannot assign requested address"
Und wird wie man sieht, von bind() verursacht. Was ist falsch?
Du musst srv_addr auch korrekt initialisieren. Du gibst hier nur den Port, nicht jedoch die Adresse an (die Adresse kann entweder die Adresse eines Interfaces sein oder eine spezielle Konstante für "JEDES INTERFACE") - und einige andere Optionen für IPv6 gibst Du auch nicht an.
In IPv4 hat laut der Manual-Seite ip(7) die Struktur sockaddr_in folgende Einträge:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
u_int16_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
Wenn Du den korrekt initialisieren willst, musst Du folgendes machen:
struct sockaddr_in srv_addr;
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = ...; // z.B. 80
srv_addr.sin_addr.s_addr = INADDR_ANY
In IPv6 (laut Manpage ipv6(7)) besitzt ein paar mehr Einträge:
struct sockaddr_in6 {
u_int16_t sin6_family;/* AF_INET6 */
u_int16_t sin6_port;/* port number */
u_int32_t sin6_flowinfo;/* IPv6 flow information */
struct in6_addr sin6_addr;/* IPv6 address */
u_int32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
sin6_flowinfo und sin6_scope_id: Wenn Du nicht weiß, was das macht, dann setze es am besten auf 0. Zudem kann es keine Konstante INADDR_ANY mehr geben, weil viele Prozessoren noch keine 128bit großen Werte unterstützen - dafür gibt's jetzt die Variable in6addr_any, die Du stattdessen verwenden kannst. Die Struktur musst Du also so korrekt initialisieren:
struct sockaddr_in6 srv_addr;
srv_addr.sin6_family = AF_INET6;
srv_addr.sin6_port = ...; // z.B. 80
srv_addr.sin6_flowinfo = 0;
srv_addr.sin6_addr = in6addr_any;
srv_addr.sin6_scope_id = 0;
Wenn Du Dich nicht an ALLE Interfaces binden willst, sondern nur an bestimmte, dann fängt die sin6_scope_id an, relevant zu werden, sprich: Dann müsstest Du Dich anfangen, mit den Details von IPv6 zu beschäftigen, weil es in Bezug Interfaces komplizierter ist, als IPv4.
Achja, evtl. hilfreich: http://www.ularx.de/studies/porting2ipv6.html
Als letztes habe ich den Code von IPv4 auf IPv6 umgerüstet. Bis dahin lief der Code einwandfrei. Habe ich was übersehen, was falsch gemacht?
Auch bei IPv4 war der Code schon fehlerhaft, da war's Zufall, dass es trotzdem funktioniert hat.
Viele Grüße,
Christian