
Организация компьютерных сетей
Штана Альберт Игоревич
В этой статье будет разобрано задание 13.
Рассмотрим типовые задачи из тринадцатого задания ЕГЭ по информатике.
Данное задание относится к повышенному уровню сложности.
Время выполнения задания ≈ 3 минуты.
Для начала давайте разберемся с терминами.
IP-адрес (Internet Protocol Address) — это уникальный числовой идентификатор, присваиваемый каждому устройству в сети. Например, 192.168.1.1
Маска подсети определяет, какая часть IP-адреса относится к адресу сети, а какая — к адресу устройства в этой сети. Маска представляется числом, например, 255.255.255.0, и состоит из единиц, обозначающих биты, принадлежащие адресу сети.
Адрес сети — это результат применения маски к IP-адресу устройства. Производится это побитовым "И" (логическим умножением) адреса узла и маски.
Для вычисления адреса сети используется следующая формула: адрес сети = IP-адрес & маска подсети, где "&" - это побитовое "И".
В терминологии сетей TCP/IP маской сети называют двоичное число, которое показывает, какая часть IP-адреса узла сети относится к адресу сети, а какая – к адресу узла в этой сети. Адрес сети получается в результате применения поразрядной конъюнкции к заданному адресу узла и маске сети.
Сеть задана IP-адресом 192.168.32.160 и маской сети 255.255.255.240. Сколько в этой сети IP-адресов, для которых сумма единиц в двоичной записи IP-адреса чётна?
В ответе укажите только число.
Можно решить данную задачу аналитически, но на экзамене не уложиться таким образом в 3 минуты. Иногда решать через программирование, а иногда лучше вручную! Первый способ "в лоб" — решить данную задачу используя Python и циклы:
count = 0
for x1 in '01':
for x2 in '01':
for x3 in '01':
for x4 in '01':
s = x1 + x2 + x3 + x4
if (8 + s.count('1')) % 2 == 0:
count += 1
print(count)
Данный способ имеет ограничение. Если количество нулей в маске превышает 20, лучше пользоваться другим способом!
from ipaddress import *
c = 0
ips = ip_network('192.168.32.160/255.255.255.240', 0)
for ip in ips:
if format(ip, 'b').count('1') % 2 == 0:
c += 1
print(c)
Задача решается в 7 строчек кода. Разберём её построчно:
Ответ: 8
В терминологии сетей TCP/IP маской сети называют двоичное число, которое показывает, какая часть IP-адреса узла сети относится к адресу сети, а какая – к адресу узла в этой сети. Адрес сети получается в результате применения поразрядной конъюнкции к заданному адресу узла и маске сети.
Сеть задана IP-адресом 253.112.169.12 и маской сети 255.255.254.0. Сколько в этой сети IP-адресов, для которых в двоичной записи IP-адреса суммарное количество единиц в правых двух байтах не менее суммарного количества единиц в левых двух байтах.
from ipaddress import *
c = 0
ips = ip_network('253.112.169.12/255.255.254.0', 0)
for ip in ips:
s = format(ip, 'b')
if s[16:].count('1') >= s[:16].count('1'):
c += 1
print(c)
Здесь перебираем все IP данной сети в виде строки s. Рассматриваем левые два байта s[:16] (первые 16 символов = 8 + 8) и правые два байта s[16:] (последние 16 символов). Если условие задачи выполняется, то подсчитываем такой IP-адрес.
Ответ: 46
В терминологии сетей TCP/IP маской сети называется двоичное число, определяющее, какая часть IP-адреса узла сети относится к адресу сети, а какая - к адресу самого узла в этой сети. Обычно маска записывается по теме же правилам, что и IP-адрес - в виде четырёх байтов, причём каждый байт записывается в виде десятичного числа. При этом в маске сначала (в старших разрядах) стоят единицы, а затем с некоторого разряда - нули. Адрес сети получается в результате применения поразрядной конъюнкции к заданному IP-адресу узла и маске.
Например, если IP-адрес узла равен 231.32.255.131, а маска равна 255.255.240.0, то адрес сети равен 231.32. 240.0.
Для узла с IP-адресом 111.81.88.168 адрес сети равен 111.81.88.160. Найдите наименьшее значение последнего байта маски. Ответ запишите в виде десятичного числа.
from ipaddress import *
ip = ip_address('111.81.88.168')
for mask in range(31):
ips = ip_network(f'{ip}/{mask}', 0)
if ips[0] < ip < ips[-1] and str(ips.network_address) == '111.81.88.160':
print(ips.netmask)
Программа распечатает 2 варианта адреса сети. Но выбираем предпоследнюю сеть, т.к. в ней последний байт маски будет с наименьшим числовым значением.
Ответ: 224
В терминологии сетей TCP/IP маской сети называется двоичное число, определяющее, какая часть IP-адреса узла сети относится к адресу сети, а какая – к адресу самого узла в этой сети. При этом в маске сначала (в старших разрядах) стоят единицы, а затем с некоторого места – нули. Обычно маска записывается по тем же правилам, что и IP-адрес – в виде четырёх байтов, причём каждый байт записывается в виде десятичного числа. Адрес сети получается в результате применения поразрядной конъюнкции к заданному IP-адресу узла и маске.
Например, если IP-адрес узла равен 231.32.255.131, а маска равна 255.255.240.0, то адрес сети равен 231.32.240.0.
Для узла с IP-адресом 93.138.70.47 адрес сети равен 93.138.64.0. Каково наибольшее возможное общее количество единиц во всех четырёх байтах маски? Ответ запишите в виде десятичного числа.
from ipaddress import *
ip = ip_address('93.138.70.47')
for mask in range(31):
ips = ip_network(f'{ip}/{mask}', 0)
if ips[0] < ip < ips[-1] and str(ips.network_address) == '93.138.64.0':
print(ips)
Аналогично прошлой задачи. В ответе в консоли остаётся только найти наш адрес сети, где максимальное количество единиц в маске. Это будет: 93.138.64.0/21
Ответ: 21
В терминологии сетей TCP/IP маской подсети называется 32-разрядное двоичное число, определяющее, какие именно разряды IP-адреса компьютера являются общими для всей подсети – в этих разрядах маски стоит 1. Обычно маски записываются в виде четверки десятичных чисел – по тем же правилам, что и IP-адреса. Для некоторой подсети используется маска 255.255.248.0.
Сколько различных адресов компьютеров допускает эта маска?
Примечание. На практике для адресации компьютеров не используются два адреса: адрес сети и широковещательный адрес.
from ipaddress import *
ips = ip_network('0.0.0.0/255.255.248.0')
print(ips.num_addresses - 2)
Здесь вообще всё элементарно просто — мы взяли произвольный адрес сети "0.0.0.0" и применили нашу маску. Свойство num_addresses покажет количество возможных адресов в этой сети. Необходимо так же вычистить два неиспользуемых адреса.
Ответ: 2046
В терминологии сетей TCP/IP маска сети – это двоичное число, меньшее 232; в маске сначала (в старших разрядах) стоят единицы, а затем с некоторого места нули. Маска определяет, какая часть IP-адреса узла сети относится к адресу сети, а какая – к адресу самого узла в этой сети. Обычно маска записывается по тем же правилам, что и IP-адрес – в виде четырёх байт, причём каждый байт записывается в виде десятичного числа. Адрес сети получается в результате применения поразрядной конъюнкции к заданному IP-адресу узла и маске.
Для узла c IP-адресом 175.122.80.13 адрес подсети равен 175.122.80.0. Сколько существует различных возможных значений маски, если известно, что в этой сети не менее 60 узлов?
Ответ запишите в виде десятичного числа.
from ipaddress import *
ip = ip_address('175.122.80.13')
c = 0
for mask in range(31):
ips = ip_network(f'{ip}/{mask}', 0)
if ips[0] < ip < ips[-1] and str(ips.network_address) == '175.122.80.0' and ips.num_addresses - 2 >= 60:
c += 1
print(c)
В условии также воспользуемся свойством num_addresses – как и в прошлой задаче и свойством network_address – как в позапрошлой задаче. Ищем те ip-адреса, где есть наш адрес сети и где количество возможных значений IP-адресов узлов не менее 60. И помним когда у нас спрашивают — Сколько? То скорее всего лучше будет завести переменную для счётчика.
Ответ: 7
Маской подсети называется 32-разрядное двоичное число, которое определяет, какая часть IP-адреса компьютера относится к адресу сети, а какая часть IP-адреса определяет адрес компьютера в подсети. В маске подсети старшие биты, отведенные в IP-адресе компьютера для адреса сети, имеют значение 1; младшие биты, отведенные в IP-адресе компьютера для адреса компьютера в подсети, имеют значение 0.
Если маска подсети 255.255.255.224 и IP-адрес компьютера в сети 162.198.0.157, то порядковый номер компьютера в сети равен_____
Данную задачу лучше решать вручную без использования ipaddress.
В этой задаче ключевой фразой является: "порядковый номер компьютера".
Первые 3 слева байты маски равны 255 (11111111), значит, они не участвуют в решении этой задачи. Обращаем внимание только на байт IP-адреса, под которым байт маски имеет не все единицы в своих разрядах.
Ответ: 29
Предположим IP адрес будет 162.198.157.10, а маска подсети 255.255.224.0, тогда запишем байты IP-адреса, а под ними байты маски:
10011101 00001010
11100000 00000000
Здесь берём всю ту часть IP-адреса, которая находится над нулями! Не ограничиваемся 8-ю разрядами!
1110100001010 = 7434
В терминологии сетей TCP/IP маской сети называют двоичное число, которое показывает, какая часть IP-адреса узла сети относится к адресу сети, а какая – к адресу узла в этой сети. Адрес сети получается в результате применения поразрядной конъюнкции к заданному адресу узла и маске сети.
Сеть задана IP-адресом 255.211.33.160 и маской сети 255.255.A.0, где A - некоторое допустимое для записи маски число. Определите минимальное значение A, для которого для всех IP-адресов этой сети в двоичной записи IP-адреса суммарное количество единиц в левых двух байтах не менее суммарного количества единиц в правых двух байтах.
from ipaddress import *
for i in range(9):
A_bin = i * '1' + ('0' * (8 - i))
A = int(A_bin, 2)
ips = ip_network(f'255.211.33.160/255.255.{A}.0', 0)
flag = True
for ip in ips:
s = format(ip, 'b')
if s[16:].count('1') > s[:16].count('1'):
flag = False
break
if flag:
print(A)
break
Разберём построчно:
Ответ: 240
В терминологии сетей TCP/IP маской сети называют двоичное число, которое показывает, какая часть IP-адреса узла сети относится к адресу сети, а какая – к адресу узла в этой сети. Адрес сети получается в результате применения поразрядной конъюнкции к заданному адресу узла и маске сети.
Сеть задана IP-адресом 32.0.A.5, где A - некоторое допустимое для записи IP-адреса число, и маской сети 255.255.240.0. Определите минимальное значение A, для которого для всех IP-адресов этой сети в двоичной записи IP-адреса суммарное количество единиц в левых двух байтах не более суммарного количества единиц в правых двух байтах.
from ipaddress import *
for A in range(256):
ips = ip_network(f'32.0.{A}.5/255.255.240.0', 0)
flag = True
for ip in ips:
s = format(ip, 'b')
if s[:16].count('1') > s[16:].count('1'):
flag = False
break
if flag:
print(A)
break
Здесь уже нужно перебирать байт IP-адреса, а не маски, значит, можно перебрать числа от 0 до 255. Далее всё как в прошлой задаче.
Ответ: 16
В терминологии сетей TCP/IP маской сети называют двоичное число, которое показывает, какая часть IP-адреса узла сети относится к адресу сети, а какая – к адресу узла в этой сети. Адрес сети получается в результате применения поразрядной конъюнкции к заданному адресу узла и маске сети. Сеть задана IP-адресом 192.168.32.160 и маской сети 255.255.255.240.
Сколько в этой сети IP-адресов, для которых сумма единиц в двоичной записи IP-адреса чётна? В ответе укажите только число.
В подобных задачах в первых двух абзацах даётся краткая теория, которая почти не меняется от задачи к задаче. Вопрос, который нас интересует, находится в последних двух абзацах.
В задаче говорится, что адрес сети получается при применении поразрядной конъюнкции к заданному IP-адресу узла и маске сети.
Адрес сети: 192.168.32.160
Маска: 255.255.255.240
Первые три байта маски равны 255. В двоичной записи это 8 единиц. Значит, первые три числа IP-адреса узла так же равны 192.168.32. как и в адресе сети. Рассмотрим последний байт:
в максе: 240 - 1111 0000
в сети: 160 - 1010 0000
IP-адрес тогда: 1010 XXXX
Получается, что возможность для изменений у нас есть только на последних 4 битах IP-адреса узла. Посчитаем, сколько у нас уже единиц точно известно в IP-адресе в двоичном виде: 192 = 11000000 (две единицы) 168 = 10101000 (три единицы) 32 = 00100000 (одна единица) Плюс две единицы в последнем байте. Тогда получается: 2 + 3 + 1 + 2 = 8 Восемь единиц уже точно есть в любом IP-адресе узла. Осталось посчитать количество вариантов, когда в 4 битах будет чётное количество единиц. Это варианты: 0000, 0011, 0101, 0110, 1001, 1010, 1100, 1111(записал для наглядности). По формуле: N = 2^i. N - кол-во вариантов IP-адресов, i - количество бит оставшихся под IP-адрес после маски. 16 = 2^4, всего 16 вариантов(чётных и нечётных) 16/2 = 8 - количество чётных(или здесь же нечётных соответственно).
Можно аналогично решать на Python, как во 2 или 8 задании с помощью циклов:
c = 0
for x1 in '01':
for x2 in '01':
for x3 in '01':
for x4 in '01':
s = x1 + x2 + x3 + x4
if s.count('1') % 2 == 0:
c += 1
print(c)
Или с помощью модуля ipaddress:
from ipaddress import *
с = 0
for ip in ip_network('192.168.32.160/255.255.255.240'):
if format(ip, 'b').count('1') % 2 == 0:
с += 1
print(с)
Здесь мы как бы "поделили" в цикле адрес сети на маску и получили ip-адреса, которые соответствуют данной сети. Далее получая в цикле по очереди IP-адреса → Функция format() переводит ip адрес в байтовую строку, где просто идут все биты ip-адреса в виде строки и тут же мы проверяем с помощью функции count количество единиц в байтовой строке IP-адреса, если кратно 2 (%2 - остаток от деления на 2), то увеличиваем счётчик с. По того как цикл отработал выводим переменную счётчика c как ответ.
Ответ: 8
Сеть задана IP-адресом 172.16.168.0 и маской сети 255.255.248.0.
Сколько в этой сети IP-адресов, для которых количество единиц в двоичной записи IP-адреса не кратно 5? В ответе укажите только число.
В задаче говорится, что адрес сети получается при применении поразрядной конъюнкции к заданному IP-адресу узла и маске сети.
Адрес сети: 172.16.168.0
Маска: 255.255.248.0
Первые два байта маски равны 255. В двоичной записи это 8 единиц. Значит, первые два числа IP-адреса узла так же равны 172.16 как и в адресе сети. Рассмотрим последний и предпоследний байты:
в максе: 248 - 1111 1000
в сети: 168 - 1010 1000
IP-адрес тогда получается путём поразрядной конъюнкции: 1010 1XXX
Получается, что возможность для изменений у нас есть только на последних 3 битах IP-адреса узла. Посчитаем, сколько у нас уже единиц точно известно в IP-адресе в двоичном виде:
172 = 1010 1100 (четыре единицы)
16 = 0001 0000 (одна единица)
Плюс три единицы в предпоследнем байте. Тогда получается: 4 + 1 + 2 = 8 Восемь единиц уже точно есть в любом IP-адресе узла.
Осталось посчитать количество вариантов, когда в оставшихся 3+8=11 битах будет не кратное к 5 количество единиц. По формуле: N = 2^i. N - кол-во вариантов IP-адресов, i - количество бит оставшихся под IP-адрес после маски. N = 2^11, всего 2048.
Чтобы получить ответ нужно от общего количества ip-адресов отнять количество ip адресов кратных 5. В таком случае когда уже имеется 8 единиц, чтобы ip-адрес по количеству единиц в двоичной записи был кратный 5, необходимо добавить 2 или 7 единиц из оставшихся 11 свободных битов под ip-адреса. Применим формулу сочетания из комбинаторики(есть статья на Яндекс Практикуме по основным формулам комбинаторики и у меня в блоге Ссылка на статью: Формулы комбинаторики — советую почитать) при добавлении 2 единиц к 11 битам: С = 11 * 10 / 2! = 55 - количество комбинаций двух единиц в 11 битах(остальные 9 битов всегда нули). При добавлении 7 единиц к 11 битам: С = 11 * 10 * 9 * 8 * 7 * 6 * 5 / 7! = 330. В сумме количество ip-адресов кратных 5 = 330 + 55 = 385.
Последнее действие это от общего количества всех ip-адресов отнять количество адресов кратных 5, чтобы получить ответ: 2048 - 385 = 1663.
from ipaddress import *
c = 0
for ip in ip_network('172.16.168.0/255.255.248.0'):
if format(ip, 'b').count('1') % 5 != 0:
c += 1
print(c)
Здесь мы в цикле как бы сделали поразрядную конъюнкцию адреса сети на маску и получили ip-адреса. Далее получая в цикле по очереди IP-адреса → Функция format() переводит ip адрес в байтовую строку, где просто идут все биты ip-адреса в виде строки и тут же мы проверяем с помощью функции count (для строк) количество единиц в байтовой строке IP-адреса, если не кратно 5 (% 5 - остаток от деления на 5), то увеличиваем переменную для счётчика на 1, инициализированную изначально выше как 0. И наконец ответ получаем в консоль.
Ответ: 1663
Сеть задана IP-адресом одного из входящих в неё узлов 191.128.66.83 и сетевой маской 255.192.0.0. Найдите в данной сети наибольший IP-адрес, который может быть назначен компьютеру. В ответе укажите найденный IP-адрес без разделителей.
Например, если бы найденный адрес был равен 111.22.3.44, то в ответе следовало бы записать: 11122344.
В задаче говорится, что адрес сети получается при применении поразрядной конъюнкции к заданному IP-адресу узла и маске сети.
Найдём адрес сети:
IP-адрес узла переводим в двоичный формат: 1011 1111. 1000 0000. 0100 0010. 0101 0011
Маска сети в двоичном формате: 1111 1111. 1100 0000. 0000 0000. 0000 0000
Применяя побитовую конъюнкцию получим IP адрес сети: 1011 1111. 1000 0000. 0000 0000. 0000 0000 = 191.128.0.0
Затем заменив все нули на единицы в IP адресе сети согласно нулей маски получим широковещательный адрес в сети: 1011 1111. 1011 1111. 1111 1111. 1111 1111 = 191.191.255.255
Осталось только отнять единицы в последнем бите, чтобы получить наибольший ip адрес для устройства в данной сети: 1011 1111. 1011 1111. 1111 1111. 1111 1110 = 191.191.255.254
from ipaddress import *
ips = ip_network('191.128.66.83/255.192.0.0', 0)
print(ips[-2]) # Наибольший адрес сети
print(ips[1]) # Наименьший адрес сети
print(ips[0]) # Адрес сети
print(ips[-1]) # Широковещательный адрес
Сначала импортируем все функции из стандартного модуля ipaddress. Далее во второй строке получили все ip-адреса. Так как все адреса находятся в списке и первый адрес из этого списка - это адрес сети, последний - это широковещательный. То второй ip адрес сначала списка(индекс 1) это наименьший адрес в сети, а второй с конца списка(индекс -2) наибольший адрес в сети. В консоль просто нужно вывести через индексатор ответ и переписать его без точек.
p.s. Если мы хотим избавиться от ip адреса сети и широковещательного, то нужно добавить .hosts(). Например, ip_network('191.128.66.83/255.192.0.0', 0).hosts()
Ответ: 191191255254
Попробуйте сами запустить код в окне ниже с интерпретатором Python и повторите примеры из статьи чтобы самим увидеть и понять как всё это работает. Для этого в ячейке с кодом нажмите клавиши на клавиатуре Shift+Enter или запустите код через кнопку Run по значку ▶.