2009-04-29 5 views
4

Je suis en train d'écrire un client/serveur de test UDP et je veux l'utiliser via un pare-feu. Supposément tout ce que je dois faire est d'avoir les deux côtés envoyer à la bonne adresse IP et le serveur. Obtenir une adresse IP n'est pas un problème, mais comment puis-je demander au client de choisir un port libre aléatoire et de le signaler à l'utilisateur? Je voudrais éventuellement le connecter à un serveur de matchmaker mais maintenant j'ai besoin d'un prototype de travail simple et je voudrais personnaliser le numéro de port afin que mon ami/testeur puisse m'envoyer le # via IM afin que nous puissions tester.Comment puis-je obtenir un port de socket libre? C++

Comment obtenir le numéro de port? désolé pour la longue desc. Je remarque que les gens me disent de ne pas faire ce que je demande quand je ne donne pas une desc :(

Répondre

5

Pour utiliser le terme très technique, il s'agit en fait d'un problème assez difficile ou même d'une paire de problèmes difficiles. En fonction de la configuration du pare-feu, il autorisera généralement les réponses d'un autre point de terminaison sur le point de terminaison IP en fonction de la provenance de la requête. Donc ... si votre ami reçoit le datagramme UDP en utilisant quelque chose comme l'appel système recvfrom(), le paramètre adresse recevra les informations de point de terminaison IP auxquelles il doit répondre. L'autre extrémité devrait donc pouvoir répondre avec sendto() en utilisant les mêmes informations d'adressage. Quelque chose comme:

/* initiator */ 
struct sockaddr_in hisaddr; 
memset(&hisaddr, 0, sizeof(hisaddr)); 
hisaddr.sin_addr.s_addr = htonl(target_ip); 
hisaddr.sin_port = htons(target_port); 
sendto(sd, msg_ptr, msg_sz, 0, (struct sockaddr*)&hisaddr, sizeof(hisaddr)); 

/* receiver */ 
struct sockaddr_in peeraddr; 
socklen_t peer_sz = sizeof(peeraddr); 
recvfrom(sd, buf_ptr, buf_sz, 0, (struct sockaddr*)&peeraddr, &peer_sz); 
/* build response */ 
sendto(sd, msg_ptr, msg_sz, 0, (struct sockaddr*)&peeraddr, peer_sz); 

Le peeraddr de l'autre côté sera votre adresse externe ou, plus correctement, l'adresse IP de votre pare-feu et le numéro de port qu'il a choisi d'utiliser. Le numéro de port que vous spécifiez dans votre code peut être complètement différent du port auquel votre ami devrait envoyer des données. En fin de compte, peu importe le port que vous choisissez d'utiliser, car le pare-feu peut envoyer et recevoir sur un port entièrement différent - c'est ce que propose Network Address Translation. Je recommande de lire RFC3235 pour quelques conseils sur la façon de surmonter cet obstacle.

La meilleure IMHO approche consiste à:

  1. Laissez le système d'exploitation choisir un port soit en appelant bind() avec un numéro de port zéro ou de sauter la liaison tout à fait
  2. Avoir le client reçoit les informations d'adresse de la prise couche (par exemple, les cinquième et sixième arguments à recvfrom() )
  3. le client envoie une réponse au noeud final recherché à l'étape précédente
  4. ajuster les configurations de pare-feu jusqu'à ce que les étapes précédentes wo rk

Bien sûr, toute la magie est dans la dernière étape. Si vous pouvez désactiver le NAT ou vous assurer que le pare-feu ne changera jamais de ports, le cliquage d'un numéro de port et le bind -ing fonctionneront également. Vous pouvez jeter un oeil à %WINDIR%\system32\drivers\etc\services (ou /etc/services en fonction de votre inclination OS) pour avoir une idée des numéros de ports réservés ou généralement utilisés.

0

En général - vous - en tant que développeur - choisissez le port Vous pouvez configurer votre application pour lire le port à partir d'un fichier de configuration ou entrée de l'utilisateur - mais aucun pare-feu magique ne va vous dire quel port utiliser ...

0

Si je comprends bien votre question, je ne suis pas sûr qu'il existe un moyen de faire ce que vous voulez par programme (et même si c'est le cas, je ne pense pas que ce soit la bonne approche.) Je pense que vous devez trouver un port qui n'est pas utilisé sur le serveur (et peut-être un port différent sur le poste client, si la communication est bidirectionnel) ET que le port doit pouvoir traverser votre pare-feu, je suppose que puisque vous dites "obtenir une IP n'est pas un problème", vous avez déjà a configuré votre pare-feu pour transférer certains ou tous les ports vers un ordinateur spécifique à l'intérieur du pare-feu? Si c'est le cas, le port que vous recherchez est l'un de ceux que vous avez transférés. Vous pouvez en choisir un arbitrairement, tant qu'aucun autre service ne fonctionne sur ce port. Les ports inférieurs à 1024 sont réservés, donc vous voulez probablement choisir un nombre plus élevé que celui-là. Vous pouvez utiliser un outil de numérisation de ports simple tel que nmap pour voir quels services sont en cours d'exécution sur votre ordinateur sur les ports et en choisir un autre. Notez que nmap peut être berné par des pare-feu et diverses règles bind lors de la création de sockets.

0

Je pense que vous êtes mieux de choisir un port fixe plutôt que de compter sur le numéro de port aléatoire choisi par le système d'exploitation.

Si vous utilisez un port aléatoire, vous devrez modifier les paramètres de votre pare-feu à chaque fois que vous exécutez le programme.

0

bind() avant d'envoyer vos données. Spécifiez le port 0 à bind(), et le système d'exploitation choisira un port inutilisé pour vous. Vous pouvez ensuite utiliser getsockname() pour savoir quel port wsa a été choisi.

Questions connexes