Идентификатор области в экземплярах Python ipaddress.IPv6Address

В настоящее время я пишу оболочку Python для библиотеки C++, которая осуществляет сетевое взаимодействие через локальные адреса IPv6. Для инициализации библиотеки необходимо выбрать сетевой интерфейс. Это делается через локальный адрес ссылки желаемого интерфейса.

На стороне C++ мы используем объекты boost address_v6. На стороне питона ipaddress.IPv6Address, казалось, идеально подходил.

Однако я не нашел способа указать идентификатор области видимости интерфейса на стороне Python.

ip = ipaddress.IPv6Address('fe80::3c4e:6a7:3f57:4cbc%12')

выдает ошибку:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python34\lib\ipaddress.py", line 1835, in __init__
    self._ip = self._ip_int_from_string(addr_str)
  File "C:\Python34\lib\ipaddress.py", line 1664, in _ip_int_from_string
    raise AddressValueError("%s in %r" % (exc, ip_str)) from None
ipaddress.AddressValueError: Only hex digits permitted in '4cbc%12' in 'fe80::3c4e:6a7:3f57:4cbc%12'

Связь по локальной сети по протоколу IPv6 практически невозможна без идентификаторов области.

Я что-то здесь упускаю или это лучший способ указать адреса локального интерфейса IPv6 в виде строки?

2 ответа

Решение

Я рекомендую использовать те же структуры, что и в модуле сокетов Python, во всех тех случаях, когда это имеет смысл. Даже если использование вашей собственной библиотеки означает, что модуль сокета Python не будет использоваться, это все равно может быть полезным, если некоторые структуры данных совместимы между ними.

Для представления IP-адреса модуль сокетов Python действительно использует строку. И эта строка может включать идентификатор области видимости, когда это необходимо.

Модуль сокетов Python также должен представлять адреса сокетов, для этого он использует кортеж, состоящий из четырех полей. Это может быть, например:

('ff02::2%eth0', 80, 0, 2)

Обратите внимание, что это представление немного избыточно, потому что идентификатор области виден как %eth0 внутри IP-адреса и как 2 (последний элемент кортежа).

((*_, sockaddr),) = socket.getaddrinfo(
    'ff02::1de:c0:face:8D%42',
    1234,
    socket.AF_INET6,
    socket.SOCK_DGRAM,
    socket.IPPROTO_UDP
)

assert sockaddr == ('ff02::1de:c0:face:8d', 1234, 0, 42)

см. https://github.com/python/cpython/pull/4724

Другие вопросы по тегам