Использование getaddrinfo () с AI_PASSIVE

Функция getaddrinfo () не только позволяет клиентским программам эффективно находить правильные данные для создания сокета для данного хоста, теоретически это также позволяет серверам подключаться к правильному сокету.

Я только что узнал об этом и начал экспериментировать с этим через Python:

from socket import *
for i in getaddrinfo(None, 22, AF_UNSPEC, SOCK_STREAM, IPPROTO_IP, AI_PASSIVE): i

дает

(2, 1, 6, '', ('0.0.0.0', 22))
(10, 1, 6, '', ('::', 22, 0, 0))

, что заставляет меня задуматься, что-то не так.

Что именно я должен делать с этими ответами? Должен ли я

  • сделать сокет listen () для всех этих ответов, или я должен
  • просто выбрать первый, который действительно работает?

Пример на странице руководства предлагает мне взять только первый и довольствоваться им, если он не содержит ошибок, но тогда я получаю соединение только через IPv4 в моем примере.

Но если я попробую все из них, мне придется беспокоиться о 2 серверных сокетах, что не нужно из-за того, что серверные сокеты IPv6 также слушают IPv4, если выполняются определенные условия (ОС, флаги сокетов и т. Д.).

Где я ошибаюсь?


РЕДАКТИРОВАТЬ: Очевидно, я не ошибаюсь, но мой компьютер делает неправильные вещи. Я использую по умолчанию /etc/gai.conf , поставляемый с OpenSUSE. Было бы неплохо, если бы кто-нибудь мог указать мне правильное направление.

РЕДАКТИРОВАТЬ 2: В данном случае strace дает следующие внутренние вызовы после чтения /etc/gai.conf (теперь с портом 54321, поскольку я думал, что использование порта 22 может иметь какое-то плохое влияние, чего не было):

socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET6, sin6_port=htons(54321), inet_pton(AF_INET6, "::", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
getsockname(3, {sa_family=AF_INET6, sin6_port=htons(38289), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(54321), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
getsockname(3, {sa_family=AF_INET6, sin6_port=htons(60866), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0
close(3)                                = 0

Очевидно, решение должно быть принято в соответствии с результатами вызовов getsockname () ...

BTW: https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/673708 и другие упомянутые там отчеты об ошибках подтверждают мои наблюдения. Некоторые люди утверждают, что новое поведение правильное, поэтому я, очевидно, придерживался использования AF_INET6 ...: - (

6
задан Community 23 May 2017 в 12:34
поделиться