Битовые операции, возможно, на первый взгляд не самые интуитивные, но как только вы их освоите, вы увидите, что их довольно легко понять. Я попытаюсь объяснить, что делает этот код, на примере 172.16.0.1/23
в виде строки netspec
.
Часть 1 — CIDR в двоичный файл
Цель состоит в том, чтобы создать двоичное представление маски подсети из заданной длины префикса CIDR. Длина префикса CIDR — это всего лишь 1
бита в маске подсети. Первая линия
final int bits = 32 - Integer.parseInt(netspec.substring(netspec.indexOf('/')+1));
находит длину префикса CIDR, получая индекс /
и анализируя целое число, следующее за ним (23
в моем примере). Это число вычитается из 32, чтобы получить число 0
в маске подсети — эти биты также называются битами хоста.
В этом примере мы знаем, что имеем дело с префиксом /23
и что его маска подсети должна выглядеть так:
n
представляет сеть (16 бит для сети класса B), s
представляет подсеть, h
представляет хост. Для нас биты сети и подсети функционально одинаковы, но я сделал различие, чтобы быть точным. Нас интересуют только биты хоста (их количество).
nnnnnnnn nnnnnnnn sssssssh hhhhhhhh
11111111 11111111 11111110 00000000
Самый простой способ сделать это - иметь 32-битное двоичное число всех 1
и «заполнить» последние 9 бит 0
. Здесь появляется вторая строка:
Вы можете игнорировать проверку bits == 32
, так как она не так актуальна и, вероятно, используется только для оптимизации.
//final int mask = (bits == 32) ? 0 : 0xFFFFFFFF - ((1 << bits)-1);
final int mask = 0xFFFFFFFF - ((1 << 9)-1);
0xFFFFFFFF
даст вам 32-битное двоичное число всех 1
. 1
сдвинутый влево на 9 бит (1 << bits
) даст вам 512, а 512 - 1
в двоичном виде будет 111111111
:
1 << 9 10 00000000
- 1 1
--------------------------------------------------
1 11111111
Когда вы вычтете эти значения, вы получите маску подсети в двоичном виде:
0xFFFFFFFF = 11111111 11111111 11111111 11111111
- (1 << 9)-1 = 1 11111111
--------------------------------------------------
11111111 11111111 11111110 00000000
Это именно та маска сети, которую мы хотели.
Примечание. Возможно, это не самый интуитивный способ вычисления двоичного значения. Мне нравится начинать с двоичного числа из всех единиц, и это число в формате int со знаком имеет десятичное значение -1
. Затем я просто сдвигаю количество бит хоста влево, и все. (Кроме того, если вы имеете дело с целыми числами размером более 32 бит, вы можете замаскировать их с помощью 0xFFFFFFFF):
(-1 << 9) & 0xFFFFFFFF
Часть 2. Двоичный код в десятичный с точками
Остальная часть кода преобразует двоичное значение в десятичное представление с точками — 255.255.254.0.
return netspec.substring(0, netspec.indexOf('/') + 1) + // part of the netspec string before '/' -> IP address
Integer.toString(mask >> 24 & 0xFF, 10) + "." + // 11111111 & 0xFF = 0xFF
Integer.toString(mask >> 16 & 0xFF, 10) + "." + // 1111111111111111 & 0xFF = 0xFF
Integer.toString(mask >> 8 & 0xFF, 10) + "." + // 111111111111111111111110 & 0xFF = 0xFE
Integer.toString(mask >> 0 & 0xFF, 10); // 11111111111111111111111000000000 & 0xFF = 0x00
Оператор return состоит из нескольких соединенных строк, начиная с IP-адреса и заканчивая десятичным представлением каждого октета. Двоичная маска сдвигается вправо на (4-n)*8
бит (где n
— номер октета), и, используя двоичное И с 0xFF, вы получаете только последние 8 бит, которые затем анализируются Integer.toString
.
Результат 172.16.0.1/255.255.254.0
.
person
pajaja
schedule
02.02.2015