Статья Автор: Деникина Н.В., Деникин А.В.

13.1 Адресация — инструмент: модуль ipaddress

Модуль ipaddress: та же теория, но кодом

Всё, что мы делали руками, умеет стандартный модуль Python. Он не заменяет понимание — он экономит время и убирает арифметические ошибки.

Модуль подключают одной строкой: import ipaddress. Дальше есть три инструмента, и путают обычно первые два.

  • ip_address('192.168.1.130') — просто адрес, без маски. Нужен, когда маска не важна.
  • ip_interface('192.168.1.130/255.255.255.192') — узел вместе с маской. Это «я и моя маска»: есть сам адрес .ip и есть .hostmask.
  • ip_network('192.168.1.130/26', strict=False) — сеть целиком. Это «вся сеть»: первый адрес, последний адрес и все, что между.

Про strict=False запомни отдельно. Если передать адрес узла, а не адрес сети, то без этого флага модуль ругнётся ошибкой. С флагом — сам обнулит хостовые биты. В задачах №13 нам всегда дают адрес узла, поэтому флаг нужен почти всегда.


Worked example

Возьмём знакомую пару: адрес 192.168.1.130 и маску 255.255.255.192 (это /26).

import ipaddress

net = ipaddress.ip_network('192.168.1.130/26', strict=False)

net.network_address     # 192.168.1.128   первый адрес (адрес сети)
net.broadcast_address   # 192.168.1.191   последний адрес (broadcast)
net.netmask             # 255.255.255.192
net.num_addresses       # 64              всего адресов = 2^H
net.prefixlen           # 26              число единиц в маске

Сравни с тем, что мы считали руками: адрес сети .128, broadcast .191, всего 64 адреса, узлов 64 − 2 = 62. Всё сходится.


Ещё примеры

Пример 1. Номер узла — через hostmask. Хостовая маска — это маска наоборот: единицы стоят там, где узел. Дальше обычное И.

i = ipaddress.ip_interface('192.168.1.130/255.255.255.192')

i.ip          # 192.168.1.130   сам адрес узла
i.netmask     # 255.255.255.192
i.hostmask    # 0.0.0.63        маска НАОБОРОТ
i.network     # 192.168.1.128/26

int(i.ip) & int(i.hostmask)   # 2   -> номер узла

Пример 2. Перебор всех адресов сети. Объект сети можно пройти циклом — именно так решаются переборные задачи.

for addr in ipaddress.ip_network('10.0.0.4/30'):
    print(addr)

# 10.0.0.4    адрес сети
# 10.0.0.5    узел
# 10.0.0.6    узел
# 10.0.0.7    broadcast

Обрати внимание: цикл выдаёт все адреса, включая служебные. Узлов здесь 4 − 2 = 2.

Пример 3. Биты и подсчёт единиц. Чтобы работать с битами, адрес переводят в число, а единицы считают через двоичную строку.

a = ipaddress.ip_address('192.168.1.130')
int(a)                      # 3232235906   32-битное число

bin(130).count('1')         # 2    единиц в байте 130
bin(int(a) >> 16).count('1')      # единиц в ЛЕВЫХ двух байтах
bin(int(a) & 0xFFFF).count('1')   # единиц в ПРАВЫХ двух байтах

▶ Try it: собери мини-решение задачи «номер узла»: создай ip_interface для 10.18.134.220/26 и напечатай int(i.ip) & int(i.hostmask). Должно получиться 28 — как мы считали руками в первой тетради.


Что делает strict=False в ip_network?


Что напечатает этот код?

net = ipaddress.ip_network('192.168.1.130/26', strict=False)
print(net.broadcast_address)

Чем ip_interface отличается от ip_network?


Сопоставьте выражение и его результат для ip_interface('192.168.1.130/255.255.255.192') и соответствующей сети.


Верно или неверно?

Загрузка...
Чтобы оставить комментарий, необходимо авторизоваться
💬
Пока нет комментариев. Будьте первым!
Печать