Чтобы использовать высокотехнологичный термин, это на самом деле довольно неприятная проблема или даже пара проблем. В зависимости от конфигурации брандмауэра он обычно позволяет отвечать на запросы от другой конечной точки на конечной точке IP по мере поступления запроса. Итак ... если ваш друг получит дейтаграмму UDP, используя что-то вроде системного вызова recvfrom()
, параметр адреса получит информацию о конечной точке IP для ответа. Поэтому другой конец должен иметь возможность ответить sendto()
, используя ту же информацию адресации. Что-то вроде:
/* 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);
peeraddr
на другой стороне будет ваш внешнего адрес или, более правильно, IP-адрес вашего брандмауэра и номер порта, который он решил использовать. Номер порта, который вы указали в коде, может быть совершенно иным, чем порт, к которому должен был отправить ваш друг. В конечном счете, не имеет значения, какой порт вы собираетесь использовать, поскольку брандмауэр может отправлять и получать на совершенно другом порту - вот что такое Network Address Translation. Я бы рекомендовал прочитать RFC3235 для некоторых советов о том, как преодолеть этот барьер.
Лучше ИМХО это:
- Пусть OS выбрать порт, либо вызов
bind()
с нулевым номером порта или пропуском привязки вообще
- Имея клиент получает информацию об адресе из гнезда слой (например, пятая и шестая аргументы
recvfrom()
)
- клиент посылает ответ на конечную точку извлеченной на предыдущем шаге
- не подправить конфигурации брандмауэра, пока предыдущие шаги его rk
Конечно, все волшебство находится на последнем шаге. Если вы можете отключить NAT или убедиться, что брандмауэр никогда не будет переключать порты, то приведение в порядок номера порта и bind
-к нему будет работать. Вы можете взглянуть на %WINDIR%\system32\drivers\etc\services
(или /etc/services
в зависимости от наклона вашей ОС), чтобы узнать, какие номера портов зарезервированы или вообще используются.