IP-адреса и маски сети
Даны IP-адрес и маска, надо найти адрес сети, широковещательный адрес или посчитать адреса с условием. В Python для этого есть готовый модуль, поэтому код получается короткий.
- 1Что проверяет номер
- 2Адрес и маска: минимум теории
- 3База: модуль ipaddress
- 4Адрес сети и наибольший адрес
- 5Условие на двоичную запись
- 6Ищем маску
- 7Узлы сети
- 8Ловушки перед экзаменом
- 9Домашка
Что проверяет номер
Есть IP-адрес и маска сети. Это не сети как предмет, а арифметика с 32-разрядными числами. На настоящих экзаменах чаще всего встречаются два вида вопросов.
Адрес сети, широковещательный адрес или наибольший адрес компьютера. Ответ это сумма чисел адреса или адрес без точек.
Узел 185.249.55.138, маска 255.255.192.0. Найдите широковещательный адрес, в ответе сумма его чисел.
Перебираем адреса сети и считаем те, что подходят под условие на двоичную запись.
Сеть 172.16.160.0, маска 255.255.240.0. Сколько адресов, у которых количество единиц кратно 2?
Ещё встречаются задачи, где маску надо найти: по адресу узла и адресу сети или по двум узлам. Всё это решается кодом, руками будем только проверять маленькие примеры.
Широковещательный адрес 185.249.63.255, сумма его чисел 752. Адресов с чётным числом единиц 2048.
Адрес и маска: минимум теории
- IP-адрес это 32 бита, записанные четырьмя числами от 0 до 255:
192.168.52.77. Одно такое число это один байт, он же октет. - Маска это тоже 32 бита: сначала идут единицы, потом нули.
255.255.240.0значит 20 единиц и 12 нулей. Короткая запись/20. - Адрес сети получается поразрядным И адреса узла и маски. Нули маски обнуляют хвост адреса.
- Широковещательный адрес это тот же адрес, но на месте нулей маски стоят единицы.
Адреса одной сети отличаются только в той части, где у маски нули. Если нулей k, адресов в сети 2^k. Первый из них это адрес сети, последний широковещательный, и компьютеру их назначить нельзя. Поэтому:
| Слово в условии | Сколько их |
|---|---|
| «адресов» | 2^k |
| «узлов», «компьютеров», «хостов» | 2^k − 2 |
В маске могут стоять только числа 0, 128, 192, 224, 240, 248, 252, 254, 255. Других нет, потому что единицы идут подряд.
Разберём руками адрес 192.168.52.77 и маску 255.255.240.0. Первые два числа маски 255, там адрес не меняется. Последнее число маски 0, там получится 0. Интересен только третий байт:
| 52 в адресе | 00110100 |
| 240 в маске | 11110000 |
| Поразрядное И | 00110000, это 48 |
Адрес сети 192.168.48.0. Нулей в маске 12, поэтому адресов 4096, а компьютеров 4094.
База: модуль ipaddress
ip_network создаёт сеть и сразу знает всё, что мы считали руками.
from ipaddress import ip_network # второй аргумент False (strict=False) разрешает дать адрес узла, а не сети net = ip_network('192.168.52.77/255.255.240.0', False) print(net.network_address) # адрес сети print(net.netmask) # маска print(net.broadcast_address) # широковещательный адрес print(net.num_addresses) # сколько адресов всего print(len(list(net.hosts()))) # сколько узлов (без адреса сети и широковещательного)
Числа те же, что в разделе 2. Маску можно писать точками (/255.255.240.0) или числом единиц (/20), результат будет один. Когда маску ищем перебором, удобно число: f'{адрес}/{m}'.
Без False запись ip_network('1.2.3.77/24') падает с ошибкой has host bits set. Если в условии дан адрес узла, а не сети, всегда пиши False.
Сеть можно перебирать циклом, а адрес записать в двоичной системе:
from ipaddress import ip_address ip = ip_address('10.0.0.1') print(f'{ip:b}') # 32 разряда print(bin(int(ip))[2:]) # ведущие нули пропали print(bin(int(ip))[2:].zfill(32)) # вернули 32 разряда
Запись f'{ip:b}' сразу даёт ровно 32 разряда с нулями слева. Её и используй. Для bin нули пришлось бы возвращать через .zfill(32), иначе количество нулей посчитается неверно.
Даны адрес узла 172.30.99.201 и маска 255.255.240.0. Найди адрес сети и сложи его четыре числа.
Маска сети 255.255.248.0. Сколько компьютеров может быть в такой сети?
Адрес сети и наибольший адрес
В настоящих условиях всегда есть длинное вступление с определениями: что такое маска, адрес сети и широковещательный адрес. Его можно читать бегло, важен вопрос в конце. Вопросов три:
- найти адрес сети;
- найти широковещательный адрес;
- найти наибольший адрес, который можно назначить компьютеру. Это широковещательный минус 1.
Ответ почти всегда записывается в одном из двух форматов: сумма четырёх чисел адреса («100.20.3.4» даёт 127) или адрес без точек («111.22.3.44» даёт 11122344).
from ipaddress import ip_network net = ip_network('185.249.55.138/255.255.192.0', False) print(net.network_address) # адрес сети print(net.broadcast_address) # широковещательный print(net.broadcast_address - 1) # наибольший адрес для компьютера ip = net.broadcast_address print(sum(ip.packed)) # сумма октетов (packed это 4 байта адреса) print(str(ip).replace('.', '')) # адрес без разделителей
ip.packed отдаёт четыре байта адреса, а sum их складывает. Адрес минус единица работает прямо в Python. Наименьший адрес для компьютера это net.network_address + 1.
Сеть задана адресом узла 77.81.143.20 и маской 255.255.248.0. Найди наибольший адрес, который можно назначить компьютеру. В ответе запиши сумму его чисел.
Условие на двоичную запись
Условия бывают такие: чётное число единиц, единиц больше, чем нулей, ровно k единиц. Цикл по net выдаёт все адреса сети по порядку, остаётся посчитать подходящие.
from ipaddress import ip_network net = ip_network('192.168.10.64/255.255.255.224') k = 0 for ip in net: # все адреса сети по порядку b = f'{ip:b}' # двоичная запись, сразу 32 разряда if b.count('1') % 2 == 0: # чётное число единиц k += 1 print(k)
Если вопрос про компьютеры, а не про адреса, перебирай net.hosts() вместо net.
Если спрашивают наибольшее или наименьшее число единиц, цикл не нужен:
from ipaddress import ip_network net = ip_network('11.45.96.0/255.255.240.0') print(max(f'{ip:b}'.count('1') for ip in net)) print(min(f'{ip:b}'.count('1') for ip in net))
Неизвестное число A в адресе
Бывает, что в адресе сети стоит неизвестный байт A, и надо найти наименьшее A, при котором условие верно для всех адресов сети. Функция all проверяет как раз это: истинно ли условие для каждого адреса.
from ipaddress import ip_network for A in range(0, 256): net = ip_network(f'172.16.{A}.0/255.255.255.240') if all(f'{ip:b}'.count('1') >= 11 for ip in net): print(A) break
Если нужно число подходящих значений A, убери break и считай k += 1.
Сеть задана адресом 10.4.16.0 и маской 255.255.252.0. Сколько в ней адресов, в двоичной записи которых ровно 8 единиц?
Ищем маску
Тут маска неизвестна. Масок всего 33, от /0 до /32, поэтому просто перебираем число единиц m.
Маска по узлу и адресу сети
from ipaddress import ip_network for m in range(0, 33): net = ip_network(f'192.168.52.77/{m}', False) if str(net.network_address) == '192.168.48.0': # адрес сети из условия print(m, net.netmask)
Подходят /20 и /21. Если спрашивают наибольшее значение третьего байта маски, ответ 248. Нужный байт можно достать так: str(net.netmask).split('.')[2].
Руками: 52 это 00110100, а 48 это 00110000. Маска должна сохранить первые четыре разряда и обнулить единицу в хвосте. 11110000 (240) это делает, 11111000 (248) тоже, а 11111100 (252) единицу уже оставит.
Если просят не байт, а количество подходящих масок, цикл тот же, только в if стоит счётчик.
Два узла
Если при какой-то маске два узла в одной сети, то и при всех более коротких масках они тоже в одной сети. Поэтому:
- «в одной сети, наибольшее число единиц»: ответ это последний подошедший
m; - «в разных сетях, наименьшее число единиц»: ответ это первый подошедший
m, условиеn1 != n2.
from ipaddress import ip_network a, b = '10.20.133.17', '10.20.141.200' for m in range(0, 33): n1 = ip_network(f'{a}/{m}', False) n2 = ip_network(f'{b}/{m}', False) if n1 == n2: last_same = m # запоминаем, ответ будет последним print(last_same)
Узел с адресом 130.44.201.7 находится в сети с адресом 130.44.192.0. Чему равно наибольшее возможное значение третьего слева байта маски?
Узлы с адресами 10.1.66.5 и 10.1.70.9 находятся в разных сетях. Каково наименьшее возможное количество единиц в маске?
Узлы сети
Узлы нумеруются с 1 по порядку, а hosts() отдаёт их без адреса сети. Превращаем в список и берём нужный. Индексы в списке начинаются с 0, поэтому 300-й узел это hosts[299].
from ipaddress import ip_network net = ip_network('10.7.64.0/255.255.252.0') hosts = list(net.hosts()) # превратили в список print(hosts[299]) # 300-й узел: индекс на 1 меньше
Если спрашивают только количество, адрес можно взять любой, важна только маска:
from ipaddress import ip_network net = ip_network('0.0.0.0/255.255.254.0') print(net.num_addresses) # адресов print(len(list(net.hosts()))) # узлов (на 2 меньше)
Руками: 254 это 11111110, один нуль, и ещё 8 нулей в последнем байте. Всего 9 нулей, адресов 2^9 = 512, узлов 510.
Сеть задана адресом 192.168.16.0 и маской 255.255.252.0. Узлы нумеруются по порядку, начиная с 1. Чему равен последний байт адреса узла с номером 500?
Ловушки перед экзаменом
| Ловушка | Как не попасться |
|---|---|
| Адреса и узлы | Адресов 2^k, это num_addresses. Узлов 2^k − 2, это hosts() |
Ошибка has host bits set | Для адреса узла всегда пиши False |
| Наибольший адрес компьютера | Это широковещательный минус 1, а не сам широковещательный |
Нули в записи bin(int(ip)) | Бери f'{ip:b}', там всегда 32 разряда |
| Сравнение адреса с текстом | network_address и netmask не строки, оборачивай в str(...) |
| Номер узла и индекс | 300-й узел это hosts[299] |
| Перебор адресов очень большой сети | В сети /8 их 16 миллионов, на сайте код упрётся в лимит 10 секунд. Когда ищешь маску, адреса перебирать не надо, хватит network_address |
| «Наименьшая маска» и «наименьший байт» | Читай, что именно просят: число единиц или значение байта |
| Формат ответа | Сумма чисел или адрес без точек: смотри пример в конце условия |
Как решать задачу
- Определи, что дано (узел, сеть, маска) и что просят (адрес, маска, количество).
- Найди слово: «адресов» или «узлов».
- Пиши цикл по
m, если ищешь маску, и цикл поnet, если считаешь адреса. - Сомневаешься в коде? Проверь его на маленькой сети:
/30даёт 4 адреса и 2 узла. - Запиши ответ в формате из условия.
Домашка
Семь задач с настоящих экзаменов и из банка ФИПИ. Решай прямо здесь: кнопка «Решать здесь» открывает редактор, а код каждой задачи сохраняется.
Перед тем как писать код, ответь себе на три вопроса по условию:
- какой адрес просят: адрес сети, широковещательный или наибольший для компьютера;
- в каком формате ответ: сумма чисел или адрес без точек;
- адресов или узлов надо посчитать, если вопрос про количество.
В задачах про компьютер не забудь вычесть 1 из широковещательного адреса. В шестой задаче ответ это адрес без точек, а не сумма. В седьмой считаем все адреса сети, поэтому цикл идёт по net, а не по hosts().
Ещё задачи этого вида и учебные задачи на поиск маски лежат в разделе «Задания», №10.
В проекте ЕГЭ-2027 эта тема стоит под №10, в ЕГЭ-2026 это был №13. Утверждённая демоверсия 2027 выйдет в ноябре, типы задач могут уточниться. Примеры и задачи «Попробуй сам» учебные, в домашке задачи с настоящих экзаменов и из банка ФИПИ.