2009-04-29 2 views
4

Я пишу тестовый клиент/сервер UDP, и я хочу получить его через брандмауэр. Предположительно, все, что мне нужно сделать, это отправить обе стороны на правильный IP-адрес и сервер. Получение IP-адреса не является проблемой, но как я могу клиент выбрать произвольный свободный порт и сообщить об этом пользователю? В конечном итоге я хотел бы, чтобы он подключился к серверу сватов, но прямо сейчас мне нужен простой рабочий прототип, и я хотел бы указать номер порта, чтобы мой друг/тестер мог отправить мне # через IM, чтобы мы могли протестировать.Как получить бесплатный порт сокета? C++

Как получить номер порта? извините за длинный desc. Я замечаю, что люди говорят мне не делать то, что я прошу, когда я не даю desc :(

ответ

5

Чтобы использовать высокотехнологичный термин, это на самом деле довольно неприятная проблема или даже пара проблем. В зависимости от конфигурации брандмауэра он обычно позволяет отвечать на запросы от другой конечной точки на конечной точке 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 для некоторых советов о том, как преодолеть этот барьер.

Лучше ИМХО это:

  1. Пусть OS выбрать порт, либо вызов bind() с нулевым номером порта или пропуском привязки вообще
  2. Имея клиент получает информацию об адресе из гнезда слой (например, пятая и шестая аргументы recvfrom())
  3. клиент посылает ответ на конечную точку извлеченной на предыдущем шаге
  4. не подправить конфигурации брандмауэра, пока предыдущие шаги его rk

Конечно, все волшебство находится на последнем шаге. Если вы можете отключить NAT или убедиться, что брандмауэр никогда не будет переключать порты, то приведение в порядок номера порта и bind-к нему будет работать. Вы можете взглянуть на %WINDIR%\system32\drivers\etc\services (или /etc/services в зависимости от наклона вашей ОС), чтобы узнать, какие номера портов зарезервированы или вообще используются.

0

Вообще говоря, вы - как разработчик - выбираете порт. Вы можете настроить приложение на чтение порта из файла конфигурации или пользовательский ввод - но никакой волшебный брандмауэр не расскажет вам, какой порт использовать ...

0

Если я правильно понимаю ваш вопрос, я не уверен, что есть способ сделать то, что вы хотите программно (и даже если есть, я не думаю, что это правильный подход). Думаю, вам нужно найти порт, который не используется на серверной машине (и, возможно, другой или тот же порт на клиентской машине, если связь двунаправленный) И этот порт должен иметь возможность проходить через ваш брандмауэр. Я предполагаю, что, поскольку вы говорите, что «получение IP-адреса не является проблемой», вы уже сотрудничаете nfigured ваш брандмауэр для пересылки некоторых или всех портов на конкретный компьютер внутри брандмауэра? Если это так, порт, который вы ищете, является одним из отправленных вами. Вы можете просто выбрать произвольное, если на этом порту не работает никакая другая служба. Порты ниже 1024 зарезервированы, поэтому вы, вероятно, захотите выбрать большее число, чем это. Вы можете использовать простой инструмент для сканирования портов, такой как nmap, чтобы узнать, какие службы запущены на вашем компьютере, на каких портах и ​​выбрать другой. Обратите внимание, что nmap можно обмануть брандмауэрами и различными правилами bind при создании сокетов.

0

Я думаю, что вам лучше выбрать фиксированный порт, а не полагаться на случайный номер порта, выбранный O/S.

Если вы используете случайный порт, вам придется менять настройки брандмауэра каждый раз при запуске программы.

0

Если вы используете Winsock Регулярно проверяйте эту ссылку: http://msdn.microsoft.com/en-us/library/aa280717(VS.60).aspx В основном у вас есть 2 варианта установка порта 0, и пусть система присвоит вам один или выбрать случайные один попытку открыть сокет, если он не работает попробуйте другой (обязательно избегайте зарезервированных портов)

0

связать() гнездо перед отправкой ваших данных. Укажите порт 0 для привязки(), и ОС выберет для вас неиспользуемый порт. Затем вы можете использовать getsockname(), чтобы узнать, какой порт был выбран.

Смежные вопросы