2010-03-05 2 views
0

En C++, quand je lance (alerte rouge! Pseudo-code)socket double UDP obligatoire dans Linux

bind(s1, <local address:port1234>) 
bind(s2, <local address:port1234>) 

sur deux sockets UDP différents (s1 et s2 chacun créé avec un appel à socket()) Je reçois des problèmes . Sous Linux (Ubuntu), la double liaison semble aller bien. Dans Windows, cependant, la liaison double échoue et l'appel à bind() la deuxième fois pour la même adresse renvoie != 0.

Je veux avoir le comportement que j'ai sur Windows sur ma machine Linux. Y at-il des paramètres que je peux travailler pour obtenir un "port occupé" sur Linux?

+1

Pouvez-vous poster du code réel? Jusqu'à ce que vous me le demandiez, j'étais sûr que vous * obteniez * une erreur la deuxième fois que vous liez. –

+3

Je pensais aussi, donc je l'ai testé. Après l'appel socket(), le second bind() sur le même port renvoie EADDRINUSE. – msw

Répondre

4

S'il vous plaît voir bind et setsockopt. À moins que vous n'ayez appelé setsockopt avec SO_REUSEADDR, votre appel de bind avec la même adresse devrait entraîner un échec avec EADDRINUSE.

+0

Vous avez raison sur l'argent! SO_REUSEADDR ne fonctionne pas de la même manière sous Windows et Linux (BSD-sockets?). –

+0

SO_REUSEADDR ne vous permet cependant pas de vous lier deux fois à un noeud final. Son but est de remplacer l'état TIME_WAIT après la fermeture d'un socket TCP. Normalement, le système d'exploitation conserve un socket TCP dans TIME_WAIT pendant quelques minutes pour récupérer les paquets "en retard" qui ne sont pas encore arrivés. Si vous essayez d'ouvrir une nouvelle socket, vous obtenez EADDRINUSE sauf si vous spécifiez SO_REUSEADDR qui détruit le socket TIME_WAIT. –

+0

@ JohnKugelman- réellement faux; Sous Linux et pour UDP, SO_REUSEADDR vous permet en fait d'avoir plusieurs sockets liés au même point de terminaison en même temps. Ceci est différent de la sémantique pour Linux + TCP et aussi différent de la sémantique sur BSD. –

0

Etes-vous sûr de ça? Selon man 7 ip sur ma boîte Linux (Fedora 9):

Lorsqu'un processus veut recevoir de nouveaux paquets entrants ou des connexions, il doit se lier à une socket à une adresse d'interface locale en utilisant bind (2). Une seule socket IP peut être liée à une paire locale donnée (adresse, port).

Il n'y a aucune mention d'une exception pour UDP de liaison dans les deux man 7 ip ou man 7 udp. (Cela ne prouve rien, mais un comportement non documenté dans quelque chose d'aussi basique que cela est ... surprenant.)

2

Ce n'est pas le comportement que j'obtiens sous Linux. Quand je lance le programme de test suivant, le second bind appel échoue avec EADDRINUSE:

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

int main() 
{ 
    int s1, s2; 
    struct sockaddr_in sa = { 
     .sin_family = AF_INET, 
     .sin_port = 0x5555, 
     .sin_addr.s_addr = INADDR_ANY }; 

    s1 = socket(PF_INET, SOCK_DGRAM, 0); 
    s2 = socket(PF_INET, SOCK_DGRAM, 0); 
    if (bind(s1, (struct sockaddr *)&sa, sizeof sa) < 0) 
     perror("bind 1"); 
    if (bind(s2, (struct sockaddr *)&sa, sizeof sa) < 0) 
     perror("bind 2"); 

    return 0; 
} 
+0

+1 pour l'exemple de code (j'étais sur le point de publier un, mais pas maintenant :-P), mais un petit nit: 'AF_INET' devrait être utilisé pour la famille d'adresses (ie, dans le champ' sin_family'). –

+0

Personnellement, j'utilise 'AF_INET' dans l'appel' socket' --- la spécification de base de groupe ouvert n'a pas de constantes 'PF_ *' --- mais je peux voir plus de cas pour "lenience" pour ' socket' et autres utilisations non-address. –

+0

À droite vous êtes monsieur, mis à jour (les pages man Linux disent d'utiliser les constantes 'PF_' pour l'argument' socket() ', mais je suis sûr qu'il n'y a pas de différence pratique). – caf