4. IP. IPv4, IPv6 и устройство сетевого пакета
Роль IP в стеке и зачем это Go-разработчику
Протокол IP (Internet Protocol) работает на третьем (сетевом) уровне модели OSI и образует фундамент глобального интернета. Если протоколы канального уровня (3. Ethernet, MAC-адреса и локальные сети) обеспечивают доставку кадров лишь в пределах одного кабеля или коммутатора, то протокол IP решает принципиально иную, грандиозную задачу: логическую сквозную адресацию и маршрутизацию пакетов через миллионы разнородных сетей планеты.
Создатели архитектуры интернета Винтон Серф и Роберт Кан заложили в IP гениальный принцип минимализма: IP — это датаграммный протокол без установления соединения с негарантированной доставкой (Best-Effort Delivery).
Протокол IP не обещает, что ваш пакет гарантированно дойдет до адресата. Он не гарантирует сохранение порядка пакетов и не защищает от дубликатов. Он дает одно лаконичное обещание: приложить максимум физических усилий, чтобы переправить пакет на один шаг (hop) ближе к целевому узлу.
Для Go-разработчика понимание устройства протокола IP критично на трех практических уровнях:
- Сетевое программирование и надежность: Конфигурирование сетевых соединений
net.Conn, тонкая настройка структурыnet.Dialer, диагностика ошибок таймаутовdial, предотвращение зависаний DNS и понимание границ между размером кадра MTU и максимальным размером сегментаTCP MSS. - Mechanical Sympathy и производительность: Выравнивание битовых полей в заголовках, аппаратная разгрузка контрольных сумм (Checksum Offloading), влияние размера заголовков на кэш-линии процессора L1/L2 и устранение паразитной фрагментации пакетов.
- Системная архитектура и масштабирование: Проектирование CIDR-подсетей микросервисов, поддержка IPv6 Dual-Stack, работа с балансировщиками нагрузки (29. Балансировка нагрузки. L4, L7, Round Robin, Least Connections) и обратными прокси-серверами (27. Прокси, Reverse Proxy и API Gateway).
flowchart TD
classDef process fill:#1e293b,stroke:#38bdf8,stroke-width:1px,color:#f8fafc
classDef success fill:#064e3b,stroke:#34d399,stroke-width:1px,color:#f8fafc
classDef error fill:#7f1d1d,stroke:#f87171,stroke-width:1px,color:#f8fafc
classDef warning fill:#78350f,stroke:#fbbf24,stroke-width:1px,color:#f8fafc
classDef entry fill:#1e3a5f,stroke:#38bdf8,stroke-width:2px,color:#f8fafc
classDef aux fill:#334155,stroke:#64748b,stroke-width:1px,color:#f8fafc
classDef system fill:#312e81,stroke:#a78bfa,stroke-width:1px,color:#f8fafc
classDef data fill:#132d29,stroke:#2dd4bf,stroke-width:1px,color:#f8fafc
classDef network fill:#881337,stroke:#fb7185,stroke-width:1px,color:#f8fafc
classDef accent fill:#1e1b4b,stroke:#818cf8,stroke-width:1px,color:#f8fafc
subgraph AppGo ["User Space (Go-приложение)"]
Dialer["net.Dialer / net.Conn"]:::process
end
subgraph LinuxKernel ["Kernel Space (Сетевой стек ядра)"]
SocketCore["Слой сокетов (sys_connect / sys_sendto)"]
TCP_Module["Транспортный уровень (tcp_ipv4 / tcp_ipv6)"]
NetfilterCore["Подсистема netfilter / iptables / xfrm"]:::process
IP_Routing["Маршрутизация IP (FIB / Route Table)"]
DevQueue["Очередь сетевых пакетов (qdisc / netdev_max_backlog)"]
end
subgraph HardwareNIC ["Сетевая карта (NIC Hardware)"]
DMA_Ring["DMA Ring Buffer (rx_ring / tx_ring)"]
Wire["Физический кабель / Оптоволокно"]:::process
end
Dialer --> SocketCore
SocketCore --> TCP_Module
TCP_Module --> NetfilterCore
NetfilterCore --> IP_Routing
IP_Routing --> DevQueue
DevQueue --> DMA_Ring
DMA_Ring --> Wire
IPv4: Устройство заголовка и ограничения
Протокол IPv4 (RFC 791) оперирует 32-битными адресами, предоставляя теоретическое пространство в $2^{32} \approx 4.29$ миллиарда уникальных адресов.
Минимальный заголовок пакета IPv4 имеет фиксированную длину 20 байт (при отсутствии дополнительных опций). При наличии опций длина может достигать 60 байт, однако в современном высоконагруженном интернете опции практически всегда отключены ради скорости аппаратной обработки.
| Битовое поле заголовка | Размер | Физическое назначение и влияние на систему |
|---|---|---|
| Version | 4 бита | Версия протокола IP. Для IPv4 здесь всегда записано число 4. |
| IHL (Internet Header Length) | 4 бита | Длина заголовка, измеряемая в 32-битных словах. Минимальное значение равно 5 ($5 \times 4 = 20$ байт). |
| DSCP / ECN | 8 бит | Классификация трафика (QoS) и флаги явного уведомления о перегрузке маршрутизатора (Explicit Congestion Notification). |
| Total Length | 16 бит | Полная длина всего IP-пакета (заголовок плюс полезная нагрузка). Максимальное значение — 65 535 байт. |
| Identification | 16 бит | Уникальный числовой идентификатор пакета, используемый для склеивания фрагментов при фрагментации. |
| Flags + Fragment Offset | 3 + 13 бит | Управление фрагментацией: флаг DF (Don't Fragment), флаг MF (More Fragments) и смещение фрагмента в 8-байтных блоках. |
| TTL (Time to Live) | 8 бит | Время жизни пакета в хопах (маршрутизаторах). Каждый маршрутизатор уменьшает TTL на единицу. При достижении 0 пакет уничтожается. |
| Protocol | 8 бит | Номер протокола следующего уровня: 6 для TCP, 17 для UDP, 1 для ICMP. |
| Header Checksum | 16 бит | Контрольная сумма исключительно самого заголовка IPv4. |
| Source / Destination IP | 32 + 32 бита | 4-байтные адреса отправителя и получателя пакета. |
flowchart TD
classDef process fill:#1e293b,stroke:#38bdf8,stroke-width:1px,color:#f8fafc
classDef success fill:#064e3b,stroke:#34d399,stroke-width:1px,color:#f8fafc
classDef error fill:#7f1d1d,stroke:#f87171,stroke-width:1px,color:#f8fafc
classDef warning fill:#78350f,stroke:#fbbf24,stroke-width:1px,color:#f8fafc
classDef entry fill:#1e3a5f,stroke:#38bdf8,stroke-width:2px,color:#f8fafc
classDef aux fill:#334155,stroke:#64748b,stroke-width:1px,color:#f8fafc
classDef system fill:#312e81,stroke:#a78bfa,stroke-width:1px,color:#f8fafc
classDef data fill:#132d29,stroke:#2dd4bf,stroke-width:1px,color:#f8fafc
classDef network fill:#881337,stroke:#fb7185,stroke-width:1px,color:#f8fafc
classDef accent fill:#1e1b4b,stroke:#818cf8,stroke-width:1px,color:#f8fafc
subgraph IPv4Header ["Анатомия заголовка IPv4 (20 байт)"]
direction TB
Row1["0..3: Version (4) | 4..7: IHL (5) | 8..15: DSCP/ECN | 16..31: Total Length"]
Row2["0..15: Identification | 16..18: Flags (DF/MF) | 19..31: Fragment Offset"]
Row3["0..7: TTL (Time to Live) | 8..15: Protocol (TCP=6/UDP=17) | 16..31: Header Checksum"]
Row4["0..31: Source IP Address (32 бита)"]
Row5["0..31: Destination IP Address (32 бита)"]
end
Mechanical Sympathy и процессорный кэш:
Заголовок IPv4 идеально выровнен по 32-битным (4-байтным) границам. Когда ядро Linux загружает 20 байт стандартного заголовка, он гарантированно помещается в одну 64-байтную кэш-линию процессора L1d вместе с началом TCP-заголовка. Однако если пакет содержит нестандартные опции IP, заголовок приобретает некратную длину. Это вызывает аппаратное расщепление строки кэша (cache line split) при последующем чтении TCP-портов, что приводит к дополнительным тактам задержки на уровне кремния CPU.
IPv6: Фиксированный заголовок и эволюция
Бурный рост мобильных устройств, облачных микросервисов и интернета вещей привел к исчерпанию глобального пула свободных адресов IPv4 в 2011 году. Архитектурным ответом индустрии стал протокол IPv6 (RFC 8200).
IPv6 — это не просто расширение разрядности адресов, а глубокое архитектурное переосмысление сетевого уровня:
- Колоссальное 128-битное адресное пространство:
IPv6 предоставляет $2^{128} \approx 3.4 \times 10^{38}$ адресов (хватит, чтобы присвоить миллионы уникальных публичных IP-адресов каждому атому на поверхности Земли!). Это устраняет необходимость в костылях трансляции адресов NAT и упрощает автоконфигурацию SLAAC (Stateless Address Autoconfiguration). - Строго фиксированный 40-байтный заголовок:
В отличие от плавающего заголовка IPv4, базовый заголовок IPv6 всегда занимает ровно 40 байт. В нем нет поля длины заголовка (IHL) и нет встроенных опций. Это позволило производителям сетевых чипов создавать сверхбыстрые кремниевые конвейеры аппаратной коммутации. - Полный отказ от контрольной суммы (No Header Checksum):
В IPv6 поле контрольной суммы заголовка отсутствует вовсе! Целостность на уровне кадров уже проверяется кодом CRC-32 в Ethernet, а целостность полезной нагрузки проверяется TCP и UDP. Отказ от контрольной суммы спас маршрутизаторы от необходимости пересчитывать математическую сумму на каждом хопе при декременте счетчика жизни пакета. - Цепочки расширенных заголовков (Extension Headers):
Любые дополнительные параметры (маршрутизация, фрагментация, шифрование IPsec) вынесены в опциональные расширенные заголовки, которые последовательно связываются полемNext Header.
| Поле заголовка IPv6 | Размер | Назначение |
|---|---|---|
| Version | 4 бита | Версия протокола (всегда число 6). |
| Traffic Class | 8 бит | Класс трафика и приоритет (аналог DSCP/ECN в IPv4). |
| Flow Label | 20 бит | Метка сквозного потока для поддержки качества обслуживания (QoS) без заглядывания внутрь TCP. |
| Payload Length | 16 бит | Размер полезной нагрузки (данные плюс расширенные заголовки). |
| Next Header | 8 бит | Тип следующего заголовка (TCP, UDP, ICMPv6 или расширенный заголовок). |
| Hop Limit | 8 бит | Лимит пересылок (точный аналог поля TTL в IPv4). |
| Source / Destination Address | 128 + 128 бит | 16-байтные адреса отправителя и получателя. |
flowchart LR
classDef process fill:#1e293b,stroke:#38bdf8,stroke-width:1px,color:#f8fafc
classDef success fill:#064e3b,stroke:#34d399,stroke-width:1px,color:#f8fafc
classDef error fill:#7f1d1d,stroke:#f87171,stroke-width:1px,color:#f8fafc
classDef warning fill:#78350f,stroke:#fbbf24,stroke-width:1px,color:#f8fafc
classDef entry fill:#1e3a5f,stroke:#38bdf8,stroke-width:2px,color:#f8fafc
classDef aux fill:#334155,stroke:#64748b,stroke-width:1px,color:#f8fafc
classDef system fill:#312e81,stroke:#a78bfa,stroke-width:1px,color:#f8fafc
classDef data fill:#132d29,stroke:#2dd4bf,stroke-width:1px,color:#f8fafc
classDef network fill:#881337,stroke:#fb7185,stroke-width:1px,color:#f8fafc
classDef accent fill:#1e1b4b,stroke:#818cf8,stroke-width:1px,color:#f8fafc
subgraph IPv6Chaining ["Механизм цепочек заголовков IPv6"]
BaseHdr["Базовый заголовок IPv6 (40B)
Next Header = Routing (43)"]:::process
RoutingHdr["Routing Extension Header
Next Header = Fragment (44)"]
FragHdr["Fragment Extension Header
Next Header = TCP (6)"]
TCPPayload["TCP Сегмент и Payload"]:::network
end
BaseHdr --> RoutingHdr
RoutingHdr --> FragHdr
FragHdr --> TCPPayload
Сравнение и переходные механизмы
Современная инфраструктура функционирует в гибридном режиме Dual-Stack, где серверы и прокси-балансировщики (28. nginx, Envoy и HAProxy. Как работают современные прокси) одновременно обрабатывают трафик стеков IPv4 и IPv6.
Ключевые технологии сосуществования и трансляции:
- Dual-Stack: Сервер слушает сокеты в режиме двойного стека (в Linux сокет
AF_INET6при сброшенном флагеIPV6_V6ONLYпрозрачно принимает как IPv6, так и IPv4-клиентов через IPv4-mapped IPv6 адреса вида::ffff:192.0.2.1). - NAT64 / DNS64: Позволяет клиентам из чистых IPv6-сетей обращаться к устаревшим IPv4-сервисам через специальный синтетический префикс и шлюз трансляции.
- Туннелирование (Teredo, 6to4): Инкапсуляция пакетов IPv6 внутрь стандартных датаграмм IPv4 для преодоления устаревших сегментов сети. Это в основном исторические механизмы: 6to4 (anycast-префикс) переведён в статус Historic (RFC 7526), и сегодня вместо них используют нативный IPv6 или NAT64.
- ICMPv6 и протокол NDP: В IPv6 полностью упразднен устаревший протокол ARP (5. ARP, Neighbor Discovery и поиск узла в локальной сети). Обнаружение соседей в локальной сети выполняется через протокол NDP (Neighbor Discovery Protocol) поверх сообщений ICMPv6.
Под капотом: Ядро Linux и работа с памятью
Когда физический IP-пакет поступает на сетевой адаптер (NIC) и через DMA сбрасывается в кольцевой буфер оперативной памяти, ядро Linux производит строгую проверку:
flowchart TD
classDef process fill:#1e293b,stroke:#38bdf8,stroke-width:1px,color:#f8fafc
classDef success fill:#064e3b,stroke:#34d399,stroke-width:1px,color:#f8fafc
classDef error fill:#7f1d1d,stroke:#f87171,stroke-width:1px,color:#f8fafc
classDef warning fill:#78350f,stroke:#fbbf24,stroke-width:1px,color:#f8fafc
classDef entry fill:#1e3a5f,stroke:#38bdf8,stroke-width:2px,color:#f8fafc
classDef aux fill:#334155,stroke:#64748b,stroke-width:1px,color:#f8fafc
classDef system fill:#312e81,stroke:#a78bfa,stroke-width:1px,color:#f8fafc
classDef data fill:#132d29,stroke:#2dd4bf,stroke-width:1px,color:#f8fafc
classDef network fill:#881337,stroke:#fb7185,stroke-width:1px,color:#f8fafc
classDef accent fill:#1e1b4b,stroke:#818cf8,stroke-width:1px,color:#f8fafc
NIC_Packet["Пакет принят из DMA Ring"]:::warning --> L2_Check{"Проверка Ethernet: MAC и VLAN"}
L2_Check -->|"Ошибка"| Drop1["Отброс кадра (Drop)"]
L2_Check -->|"Успех"| IP_Checksum{"Проверка IPv4 Checksum"}
IP_Checksum -->|"Битый заголовок"| Drop2["Отброс пакета (Drop)"]
IP_Checksum -->|"Корректно"| RouteLookup{"Поиск в таблице маршрутов FIB"}
RouteLookup --> NetfilterHook["Хуки netfilter (PREROUTING / iptables)"]
NetfilterHook --> TargetDecision{"Пакет предназначен локальному хосту?"}
TargetDecision -->|"Да: LOCAL_IN"| DeliverL4["Передача в сокет TCP/UDP (sk_buff)"]
TargetDecision -->|"Нет: FORWARD"| TTL_Check{"TTL / Hop Limit > 1?"}
TTL_Check -->|"Нет"| ICMP_TimeExceeded["Отправка ICMP Time Exceeded (Drop)"]
TTL_Check -->|"Да"| RouteForward["Декремент TTL и пересылка следующему шлюзу"]
- Слой L2: Ядро сверяет MAC-адрес и VLAN-тег.
- Валидация IP-заголовка: Проверяется длина пакета и контрольная сумма (для IPv4).
- Маршрутизация (Route Lookup): Поиск адреса назначения в системной таблице FIB (6. Маршрутизация. Таблица маршрутов, шлюзы и default route).
- Фильтрация Netfilter: Пакет проходит цепочки хуков подсистем
iptablesиnftables(32. Firewall, iptables, nftables и базовая фильтрация трафика). - Доставка в сокет: Если пакет предназначен локальному хосту, он передается модулям
tcp_ipv4илиtcp_ipv6и помещается в приемный буфер сокетаsk_buff. - Контроль зацикливания (только при пересылке): Если пакет транзитный, перед отправкой дальше (в
ip_forward) проверяется и декрементируется TTL / Hop Limit. Если он исчерпан, ядро отбрасывает пакет и генерирует диагностическое сообщение ICMP Time Exceeded (на этом механизме построена утилитаtraceroute). Для локально доставляемых пакетов TTL не декрементируется.
Оптимизация в Go: Современные сетевые адаптеры аппаратно поддерживают вычисление контрольных сумм (Checksum Offloading). Сетевая карта сама считает чексуммы TCP и UDP при передаче. В коде на Go при передаче потоков через net.Conn и буферизованный ввод-вывод bufio вычисление контрольных сумм прозрачно делегируется аппаратуре. А при отправке и приеме датаграмм UDP через методы (*net.UDPConn).WriteMsgUDP, ReadMsgUDP (или системные вызовы sendmsg/recvmsg) с флагом MSG_MORE ядро взаимодействует с сетевым адаптером напрямую, обрабатывая служебные управляющие структуры CMsg без лишних переаллокаций.
Реализация в Go: от net.IP к net/netip
На протяжении первого десятилетия существования языка Go (начиная с релиза Go 1.0) работа с IP-адресами строилась вокруг типа net.IP. Исторически тип net.IP был определен как срез байт:
type IP []byte
Это раннее архитектурное решение несло в себе тяжелые скрытые проблемы:
- Срез — это ссылочный тип, аллоцируемый в управляемой куче (Heap allocation при каждом парсинге адреса).
- Срезы в Go мутабельны: любой сторонний метод мог непреднамеренно изменить байты внутри адреса.
- Тип
net.IPнельзя было сравнивать через стандартный оператор равенства==, и его нельзя было использовать в качестве ключа хэш-таблицыmap[net.IP]T! - Парсинг миллионов IP-адресов создавал колоссальное давление на сборщик мусора GC.
В версии Go 1.18 выдающийся инженер Брэд Фицпатрик разработал революционный пакет net/netip, ставший эталоном Zero-Allocation архитектуры.
package main
import (
"fmt"
"net/netip"
)
func main() {
// 1. Быстрый парсинг IPv4 и IPv6 без единой аллокации в куче!
ipv4, err := netip.ParseAddr("192.168.1.1")
if err != nil {
panic(err)
}
ipv6, err := netip.ParseAddr("2001:db8::1")
if err != nil {
panic(err)
}
// 2. Мгновенная проверка типа адреса
fmt.Println("Is IPv4:", ipv4.Is4(), "Is IPv6:", ipv6.Is6()) // true, true
// 3. Высокопроизводительная работа с бесклассовыми префиксами подсетей (CIDR)
prefix4, err := netip.ParsePrefix("192.168.1.0/24")
if err != nil {
panic(err)
}
fmt.Printf("Подсеть: %s, Маска: %d бит\n", prefix4.Addr(), prefix4.Bits())
// 4. Проверка принадлежности IP-адреса диапазону подсети за O(1)
if prefix4.Contains(ipv4) {
fmt.Println("Адрес 192.168.1.1 входит в доверенную локальную подсеть")
}
}
flowchart LR
classDef process fill:#1e293b,stroke:#38bdf8,stroke-width:1px,color:#f8fafc
classDef success fill:#064e3b,stroke:#34d399,stroke-width:1px,color:#f8fafc
classDef error fill:#7f1d1d,stroke:#f87171,stroke-width:1px,color:#f8fafc
classDef warning fill:#78350f,stroke:#fbbf24,stroke-width:1px,color:#f8fafc
classDef entry fill:#1e3a5f,stroke:#38bdf8,stroke-width:2px,color:#f8fafc
classDef aux fill:#334155,stroke:#64748b,stroke-width:1px,color:#f8fafc
classDef system fill:#312e81,stroke:#a78bfa,stroke-width:1px,color:#f8fafc
classDef data fill:#132d29,stroke:#2dd4bf,stroke-width:1px,color:#f8fafc
classDef network fill:#881337,stroke:#fb7185,stroke-width:1px,color:#f8fafc
classDef accent fill:#1e1b4b,stroke:#818cf8,stroke-width:1px,color:#f8fafc
subgraph LegacyGo ["Исторический подход: net.IP (Go 1.0)"]
SlicePtr["Срез []byte в Heap (24 байта структуры + память в куче)"]
GC_Pressure["Мутабельный, не сравнивается через ==, нагрузка на GC"]:::system
end
subgraph ModernGo ["Современный стандарт: netip.Addr (Go 1.18+)"]
ValueType["Структура фиксированного размера [4]byte или [16]byte"]
ZeroAlloc["Иммутабельный, Zero-Alloc, сравнивается через ==, ключ для map"]:::accent
end
SlicePtr -.->|"Эволюция в Go 1.18+"| ValueType
Почему пакет net/netip кардинально превосходит старый подход:
- Чистый тип-значение (Value Type): Структура
netip.Addrхранит адрес во внутреннем фиксированном массиве[4]byteили[16]byte. Адрес передается по значению через регистры процессора, исключая аллокации в куче, лишние указатели и интерфейсные обёрткиinterface{}. - Потокобезопасность и иммутабельность: Адрес невозможно случайно мутировать из другой горутины.
- Совместимость с
map: Структурыnetip.Addrиnetip.Prefixподдерживают прямое сравнение через оператор==, позволяя использовать их в качестве сверхбыстрых ключей хэш-таблиц для черных/белых списков IP и маршрутизаторов. - Мгновенные преобразования: Конструкторы
AddrFrom4/AddrFrom16, методыAs4/As16иUnmap()выполняются за $O(1)$ без обращения к куче, идеально интегрируясь с сетевым поллером (38. Как Go работает с сетью. net, net/http, netpoller, epoll).
Ловушки и вопросы с собеседований
- Терминологическая ловушка: TTL против Hop Limit:
В заголовке IPv4 поле называется TTL (Time to Live), а в IPv6 — Hop Limit. Несмотря на название «Time to Live», в IPv4 это поле никогда не измерялось в секундах: это счетчик промежуточных узлов маршрутизации. Не путайте сетевой TTL с таймаутами HTTP-запросов или временем жизни DNS-записей! - Ошибки фрагментации и MTU:
Если UDP-пакет превышает размер MTU, а флаг DF запрещает фрагментацию, ядро возвращает приложению ошибку операционной системыMessage too long. В протоколе TCP подобное рассогласование приводит к зависанию сессий (39. TIME_WAIT, Port Exhaustion и другие проблемы TCP-сервисов) и «черным дырам» PMTUD. - Управление низкоуровневыми сокетами в Go:
Стандартный методnet.Dial()скрывает нюансы сетевого уровня. Если сервису требуется тонкая настройка параметров IP-уровня (установка битов DSCP для приоритезации трафика или привязка к конкретному интерфейсу), используют структуруnet.ListenConfig{Control: ...}или кастомный методDialContext. - Нюансы Dual-Stack и тайминги подключения:
По умолчаниюnet.Dialerиспользует алгоритм Happy Eyeballs (RFC 8305): он параллельно инициирует попытки подключения по IPv6 и IPv4 с небольшой задержкой (обычно 300 мс). Если IPv6-маршрут на сервере настроен некорректно, клиент не зависает на минуту, а быстро переключается на рабочий канал IPv4.
Итог
- Сетевой уровень L3: Протокол IP обеспечивает логическую сквозную адресацию и маршрутизацию пакетов между гетерогенными сетями планеты по принципу Best-Effort Delivery.
- IPv4 против IPv6: IPv4 использует 32-битные адреса и заголовок переменной длины (20–60 байт) с контрольной суммой. IPv6 предлагает 128-битные адреса, строго фиксированный 40-байтный заголовок без контрольной суммы и цепочки расширенных заголовков.
- Ядро Linux: Обрабатывает IP-пакеты через подсистемы
netfilter, таблицы маршрутизации FIB и сетевые очереди сокетовsk_buff. - Современный стандарт Go: Начиная с Go 1.18, всю работу с IP-адресами необходимо вести через безаллокационный пакет
net/netip(netip.Addr,netip.Prefix), полностью отказавшись от устаревшего срезаnet.IP. - Борьба с фрагментацией: Фрагментация IP-пакетов убивает сетевую производительность. Всегда контролируйте согласованность
MTUи размера сегментовTCP MSS.
Мы разобрали, как устроены сетевые IP-пакеты и адресация третьего уровня. Но как компьютер, зная только IP-адрес соседа по локальной сети, находит его физический MAC-адрес канального уровня?
В следующей лекции мы изучим протоколы связывания L2 и L3: разберем работу протокола ARP в IPv4 и протокола Neighbor Discovery в IPv6 в 5. ARP, Neighbor Discovery и поиск узла в локальной сети.