Как найти локальный / эфремальный номер порта?
У меня есть клиентская программа UDP, которая использует сокеты Berkley и Winsock (в зависимости от платформы).
В основном это использует getaddrinfo()
, затем socket()
, затем sendto()
, sendto()
принимает информацию об адресе, возвращенную getaddrinfo()
, Мой код выглядит так:
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_socktype = SOCK_DGRAM;
struct addrinfo *address;
getaddrinfo("127.0.0.1", "9999", &hint, &address);
SOCKET s = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
sendto(s, "test", 4, 0, address->ai_addr, address->ai_addrlen);
У меня вопрос, когда установлен локальный / эфемерный номер порта? Это установлено с вызовом sendto()
? Если я отправлю больше данных на другой сервер, sendto()
повторно использовать один и тот же эфемерный номер порта? Как я могу получить эфемерный номер порта (независимо от протокола)? Я знаю, что знание этого может быть бесполезным, и NAT все равно может это изменить, но я просто пытаюсь понять, как все это работает лучше.
Я также знаю, что могу использовать bind()
установить локальный порт, но мой вопрос о том, что происходит, когда ОС выбирает локальный порт для меня.
3 ответа
Вы хотите getsockname
функция:
struct sockaddr_storage ss;
socklen_t len;
len = sizeof(ss);
if (getsockname(s, (struct sockaddr *)&ss, &len) == 0) {
// print contents of ss
}
Населяет данное sockaddr
с адресом и портом, к которому привязан сокет.
Эта функция доступна как в розетках winsock, так и в Berkely.
Документация MSDN для sendto()
состояния:
Примечание. Если сокет открыт,
setsockopt
звонок сделан, а затемsendto
вызов сделан, Windows Sockets выполняет неявноеbind
вызов функции.Если сокет не связан, уникальные значения присваиваются локальной ассоциацией системой, и сокет затем помечается как связанный. Если розетка подключена,
getsockname
Функция может быть использована для определения локального IP-адреса и порта, связанного с сокетом.Если розетка не подключена,
getsockname
Функция может использоваться для определения номера локального порта, связанного с сокетом, но в качестве возвращаемого IP-адреса задается подстановочный адрес для данного протокола (например,INADDR_ANY
или "0.0.0.0" для IPv4 иIN6ADDR_ANY_INIT
или "::" для IPv6).
Вы можете bind
в порт ноль (0
) который заставит ОС найти открытый эфемерный порт, который вы можете обнаружить с помощью getsockname
или вернуть EADDRINUSE
еще до того, как вы пытались что-либо отправить.
Что касается того, когда операционная система выделяет временный порт, со страницы руководства ip(7) Linux:
[...] Эфемерный порт выделяется сокету при следующих обстоятельствах:
номер порта в адресе сокета указывается как 0 при вызове
bind(2)
;
listen(2)
вызывается на сокете потока, который ранее не был связан;
connect(2)
был вызван на сокет, который ранее не был связан;
sendto(2)
вызывается на сокете дейтаграммы, который ранее не был связан.