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 à:
- 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
- Avoir le client reçoit les informations d'adresse de la prise couche (par exemple, les cinquième et sixième arguments à
recvfrom()
)
- le client envoie une réponse au noeud final recherché à l'étape précédente
- 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.