Навигация по странице
О задании
В прошлых статьях мы не только разобрались с работой модели OSI, но и научились пользоваться функциями модуля ipaddress в Python. Теперь можем смело переходить к разбору алгоритмов решения 13 заданий ЕГЭ по информатике.
Данное задание направлено на проверку умений определять параметры по заданному IP-адресу и маске подсети, рассчитывать количество возможных адресов в сети, а также на применение побитовых операций для работы с IP-адресами и масками.
Работать в данном задании предстоит всего с тремя значениями: адрес сети, адрес узла и маска подсети. Два из них даются в условии, а одно требуется найти. Задания 13 можно разделить на 7 типов, в зависимости от данных значений:
- Даны адрес узла и маска. Чаще всего в таких заданиях требуется найти наибольший адрес сети, который может быть назначен компьютеру;
- Даны два адреса узлов, находящихся в одной сети. Требуется найти маску (наибольшее/наименьшее количество единиц/нулей в маске) или количество адресов в этой сети;
- Даны адрес узла и адрес сети. Обычно требуется найти маску подсети (наибольшее/наименьшее количество единиц/нулей);
- Даны адрес сети и маска. Требуется найти количество адресов в сети, удовлетворяющих условию, например, количество нулей/единиц в IP-адресе кратно какому-то числу и т.д.;
- Даны маска и адрес узла с неизвестным байтом. Требуется найти значение отсутствующего байта адреса узла, при котором будет выполняться условие (количество единиц/нулей в левых двух байтах меньше/больше количества в правых двух байтах);
- Даны маска и адрес сети с неизвестным байтом. Требуется найти значение отсутствующего байта адреса сети, при котором будет выполняться условие (количество единиц/нулей в левых двух байтах меньше/больше количества в правых двух байтах);
- Даны адрес сети и маска с неизвестным байтом. Требуется найти значение отсутствующего байта маски, при котором будет выполняться условие (количество единиц/нулей в левых двух байтах меньше/больше количества в правых двух байтах);
Типов слишком много для одной статьи, так что мы разобьём их разбор на три части. В данной статье рассмотрим первые 2 типа заданий, в следующей поговорим про ручные и программные методы решения 3-4 типов, а напоследок разберём все задания с неизвестным байтом.
Алгоритм решения
Решать 13 задания мы будем по большей части программными методами с помощью встроенного в Python модуля ipaddress. Если вы еще не умеете работать с данным модулем, то настоятельно рекомендуем сначала ознакомиться с прошлой статьёй.
Во всех формулировках заданий далее мы будем опускать общую часть и приводить только основную информацию, нужную для решения.
Тип 1
Начнём с самого простого типа, задания которого удивительно часто стали попадаться на экзамене.
Рассмотрим такую формулировку:
Задание 1322
«Сеть задана IP-адресом одного из входящих в неё узлов 98.81.154.195 и сетевой маской 255.252.0.0.
Найдите наибольший в данной сети IP-адрес, который может быть назначен компьютеру.»
Здесь буквально всё решение занимает пару строчек. Сначала импортируем функцию ip_interface() и создаём объект IP-интерфейса:
from ipaddress import ip_interface
net = ip_interface('98.81.154.195/255.252.0.0')
Вспоминаем, что последний (с индексом -1) адрес является широковещательным. Значит, нам нужно взять предпоследний (с индексом -2) и вывести на экран:
from ipaddress import ip_interface
net = ip_interface('98.81.154.195/255.252.0.0')
print(net.network[-2])
Мы получаем такой адрес: 98.83.255.254. Осталось лишь удалить из него точки и записать в ответ.
Пример 1
Рассмотрим задание немного посложнее:
Задание 1332
«Сеть задана IP-адресом одного из входящих неё узлов 190.202.83.62 и сетевой маской 255.255.252.0.
Найдите наибольший IP-адрес в данной сети, который может быть назначен компьютеру. В ответе укажите сумму числовых значений октетов найденного IP-адреса.»
Уже интереснее, здесь нужно не только найти адрес, но и просуммировать значения его октетов. С первой частью мы справимся без проблем:
from ipaddress import ip_interface
net = ip_interface('190.202.83.62/255.255.252.0')
last_ip = net.network[-2]
Теперь нужно как-то из переменной last_ip достать значения, разделённые точками. Сделаем это через списочное включение:
from ipaddress import ip_interface
net = ip_interface('190.202.83.62/255.255.252.0')
last_ip = net.network[-2]
octets = [int(octet) for octet in str(last_ip).split(".")]
Что у нас тут происходит? Для начала мы приводим объект IP-адреса к строчному типу данных: str(last_ip). Затем разделяем строку по символу точки: str(last_ip).split(«.»).
Проходимся по полученному списку и каждую строку в нём приводим к целочисленному типу данных: int(octet) for octet in str(last_ip).split(«.»). В конце собираем все целые числа в один список, чтобы проще было просуммировать их.
Для любителей функции map() — те же действия можно записать так:
octets = map(int, str(last_ip).split("."))
Останется лишь вывести на экран сумму чисел в списке octets:
from ipaddress import ip_interface
net = ip_interface('190.202.83.62/255.255.252.0')
last_ip = net.network[-2]
octets = [int(octet) for octet in str(last_ip).split(".")]
print(sum(octets))
Запускаем программу и получаем число 729, которое и запишем в ответ.
Пример 2
И для закрепления рассмотрим еще одно задание:
Задание 1330
«Сеть задана IP-адресом одного из входящих в неё узлов 191.128.66.83 и сетевой маской 255.192.0.0.
Найдите в данной сети наибольший IP-адрес, который может быть назначен компьютеру. В ответе укажите найденный IP-адрес без разделителей.»
Что же, не будем просто дублировать одинаковый код. Давайте в этот раз покажем максимально «питоническое» решение в одну строку:
from ipaddress import ip_network
print(ip_network('191.128.66.83/255.192.0.0', False)[-2])
А если чувствуете, что можете ошибиться в переписывании адреса с этими точками-разделителями, то лучше вовсе избавиться от них вот таким образом:
from ipaddress import ip_network
net = ip_network('191.128.66.83/255.192.0.0', strict=False)
print(str(net[-2]).replace('.',''))
В результате получим строку 191191255254, которую можно сразу записать в ответ.
Тип 2
Задания второго типа чаще всего имеют только авторские формулировки. Но в любом случае будет полезно научиться их решать. Начнём с такого:
Задание 1319
«Два узла, находящиеся в одной сети, имеют IP-адреса 127.0.1.65 и 127.0.1.101.
Укажите наименьшее возможное количество адресов в этой сети.»
Определим алгоритм действий:
- Сначала создадим по объекту на каждый IP-адрес;
- Затем в цикле будем перебирать возможные префиксы маски. Так как нам нужно наименьшее количество адресов, то следует начать со значения 30 и идти на убывание с шагом 1;
- Строим сеть по первому IP-адресу (любому из двух);
- Проверяем, попадает ли второй в эту же сеть;
- Дополнительно проверяем, что оба адреса не служебные — не адреса сети и не широковещательные.
Переходим к решению. Импорт и создание объектов:
from ipaddress import ip_network, ip_address
ip1 = ip_address('127.0.1.65')
ip2 = ip_address('127.0.1.101')
Далее перебираем значения маски от 30 до 0 с шагом 1:
from ipaddress import ip_network, ip_address
ip1 = ip_address('127.0.1.65')
ip2 = ip_address('127.0.1.101')
for mask in range(30, -1, -1):
Строим сеть по первому адресу:
from ipaddress import ip_network, ip_address
ip1 = ip_address('127.0.1.65')
ip2 = ip_address('127.0.1.101')
for mask in range(30, -1, -1):
net = ip_network(f'{ip1}/{mask}', strict=False)
Теперь проверим условия:
- ip2 входит в сеть net;
- ip1 и ip2 — не служебные. Здесь удобно будет проверить принадлежность к net.hosts().
from ipaddress import ip_network, ip_address
ip1 = ip_address('127.0.1.65')
ip2 = ip_address('127.0.1.101')
for mask in range(30, -1, -1):
net = ip_network(f'{ip1}/{mask}', strict=False)
if ip2 in net and ip1 in net.hosts() and ip2 in net.hosts():
Как только выполнится условие — выводим количество адресов в этой сети и завершаем цикл:
from ipaddress import ip_network, ip_address
ip1 = ip_address('127.0.1.65')
ip2 = ip_address('127.0.1.101')
for mask in range(30, -1, -1):
net = ip_network(f'{ip1}/{mask}', strict=False)
if ip2 in net and ip1 in net.hosts() and ip2 in net.hosts():
print(net.num_addresses)
break
Здесь требуется количество всех адресов, так что никаких «-2» мы не делаем. Запускаем программу и видим число 64. Его и запишем в ответ.
Пример 1
Заключительное задание будет таким:
Задание 1306
«Два узла, находящиеся в одной сети, имеют IP-адреса 192.168.190.12 и 192.168.184.0.
Укажите наибольшее возможное количество единиц в маске этой сети.»
Сразу вспоминаем, что количество единиц в маске — это как раз длина префикса, которую мы и перебираем в цикле. Значит, теперь нужно будет вывести на экран значение переменной mask. В остальном код практически без изменений:
from ipaddress import ip_network, ip_address
ip1 = ip_address('192.168.190.12')
ip2 = ip_address('192.168.184.0')
for mask in range(30, -1, -1):
net = ip_network(f'{ip1}/{mask}', strict=False)
if ip2 in net and ip1 in net.hosts() and ip2 in net.hosts():
print(mask)
break
Запускаем его и получаем число 20, которое и будет ответом на это задание.
На это и закончим разбор первых 4 типов 13 заданий. В следующей статье научимся решать оставшиеся 3 типа, в которых предстоит работать с неизвестными байтами в маске и адресах сети или узла.
Пример 2
Напоследок решим задание посложнее:
Задание 1333
«Два узла, находящиеся в разных подсетях, имеют IP-адреса 192.168.34.17 и 192.168.45.91. Известно, что в масках обеих подсетей содержится одинаковое количество единиц.
Определите наименьшее возможное количество единиц в масках этих подсетей.»
Снова ищем количество единиц, но теперь узлы находятся уже в разных сетях! И теперь нам не обойтись без построения обеих сетей.
Начинаем как обычно, импортируем функции и создаём два объекта IP-адреса:
from ipaddress import ip_network, ip_address
ip1 = ip_address('192.168.34.17')
ip2 = ip_address('192.168.45.91')
Видим одинаковые числа в первых двух байтах, так что уверенно заявляем, что маска меньше 16 быть не может:
from ipaddress import ip_network, ip_address
ip1 = ip_address('192.168.34.17')
ip2 = ip_address('192.168.45.91')
for mask in range(16, 31):
Теперь строим сети с разными узлами, но одинаковой длиной префикса (или маской):
from ipaddress import ip_network, ip_address
ip1 = ip_address('192.168.34.17')
ip2 = ip_address('192.168.45.91')
for mask in range(16, 31):
net_1 = ip_network(f'{ip1}/{mask}', strict=False)
net_2 = ip_network(f'{ip2}/{mask}', strict=False)
Что нам нужно проверить здесь? Во-первых, что сети разные, то есть не равны друг другу. Во-вторых, что первый IP-адрес не является служебным и входит в первую сеть. Аналогично и со вторым:
from ipaddress import ip_network, ip_address
ip1 = ip_address('192.168.34.17')
ip2 = ip_address('192.168.45.91')
for mask in range(16, 31):
net_1 = ip_network(f'{ip1}/{mask}', strict=False)
net_2 = ip_network(f'{ip2}/{mask}', strict=False)
if (net_1 != net_2 and
ip1 in net_1.hosts() and
ip2 in net_2.hosts()):
Нам нужно наименьшее количество единиц в маске, следовательно и наименьшая длина префикса. Тогда, как только выполнятся все условия, выводим текущее значение переменной mask на экран и завершаем цикл:
from ipaddress import ip_network, ip_address
ip1 = ip_address('192.168.34.17')
ip2 = ip_address('192.168.45.91')
for mask in range(16, 31):
net_1 = ip_network(f'{ip1}/{mask}', strict=False)
net_2 = ip_network(f'{ip2}/{mask}', strict=False)
if (net_1 != net_2 and
ip1 in net_1.hosts() and
ip2 in net_2.hosts()):
print(mask)
break
Готово, теперь запускаем код и радуемся ответу на это задание — числу 21.
На этом мы закончим с первыми двумя типами 13 заданий. В следующей статье разберём типы посложнее и также научимся решать некоторые из них ручными методами.