Всем привет, я жареная рыба.
Когда я писал эту статью, был первый день нового года, и изначально я хотел сказать, что Go1.18 выйдет в этом месяце. Но, молодец, вышла Go1.18 beta2, и официал сообщил сообществу, что Go1.18 будет отложен до марта, гугугу...
Как показано ниже:

Поэтому нам все еще нужно продолжать изучать новые функции.Сегодня Jianyu объединится с Брэдом Фитцпатриком « netaddr.IP: новый тип IP-адреса для Go [1] », чтобы показать вам причину появления новой сетевой библиотеки Go1.18 net/. неттип.
фон
Большой босс уходит в отставку
Брэд Фитцпатрик, который был в первоначальной команде разработчиков Go, работал в команде Go с 2010 по 2020 год и сменит компанию в 2021 году.
Следующий твит:

Причина ухода: я слишком долго занимаюсь одним и тем же, мне немного скучно, я не хочу застрять в удобном затруднительном положении.
Теперь кажется, что я переключился на Tailscale для работы, связанной с WireGuard, и мне часто приходится иметь дело с сетевыми библиотеками.
Спрос рождается
Tailscale, написанный Big Brother, по сути является сетевым приложением, для работы с сетью и написанным на Go будет задействована стандартная библиотека net
:
-
Используется для одного типа IP net.IP
. -
используется в сетевом представлении net.IPNet
.
Образец кода:
import (
"fmt"
"net"
)
func main() {
fmt.Println(net.IPv4(8, 8, 8, 8))
}
Выходной результат:
8.8.8.8
Когда Брэд Фитцпатрик на самом деле написал и использовал ее, он обнаружил, что есть много проблем с типом сетевой стандартной библиотеки, которую очень сложно использовать.
в чем проблема сейчас
Брэд Фитцпатрик перечислил проблемы стандартной библиотеки net.IP прямо в статье, с полной аргументацией.
Всего 7 основных вопросов:
-
Это изменчиво. net.IP
Базовым типом является[]byte
, что означает, что все, что вы ему передаете, может изменить его. -
Это не сравнимо. Поскольку срезы в Go несопоставимы, это означает net.IP
, что==
сравнения операторов Go не поддерживаются и не могут использоваться в качестве ключей сопоставления. -
Он имеет два типа IP-адресов, которые могут раздражать при использовании net.IP
или выборе.net.IPAddr
-
Это огромная. Go net.IP
состоит 2 частей: 24-байтового заголовка слайса и 4/6-байтового IP-адреса. Если это так, поле Zonenet.IPAddr
также будет включено. -
Он будет выделять память в куче. Net-пакет Go распределен повсюду, что требует больше работы от сборщика мусора. -
Это не разборчиво. При анализе IP-адреса из строковой формы тип IP-адреса Go не может различать адреса IPv6, сопоставленные с IPv4, и адреса IPv4. -
Это прозрачный тип, net.IP
определяемый как:type IP []byte
, является частью общедоступного API и не может быть изменен.
Брэд также упомянул, что некоторые из дизайнов были созданы в начале года, когда они были неопытными или плохо продуманными.
Теперь он ограничен обещанием совместимости с Go1 и не может быть изменен (обоюдоострый меч гарантий совместимости?).
Это реальная версия «Поедание собственной собачьей еды», поэтому в Tailscale он переделал еще одно колесо , inetaf/netaddr [2] , и хотел добавить его в стандартную библиотеку.
будущее, которое ты хочешь
Сравнительная таблица выглядит следующим образом:
характеристика | Старая схема net.IP | новый план |
---|---|---|
Неизменный | ❌, ломтик | ✅ |
сопоставимый | ❌, ломтик | ✅ |
Маленький след | ❌, 28~56 байт | ✅, фиксированные 24 байта |
не размещается в куче | ❌ | ✅ |
Поддерживает IPv4 и IPv6 | ✅ | ✅ |
Различие между IPv4 и IPv6 | ❌ | ✅ |
Поддержка зоны IPv6 | ❌ | ✅ |
непрозрачный тип | ❌ | ✅ |
Взаимодействие со стандартной библиотекой | ✅ | 🤷, необходимо адаптировать метод |
То, что я хочу, на самом деле является требованием от реального бизнеса Брэда, который должен поддержать 7 пунктов, упомянутых выше.
решение
текущий прогресс
Результат реализации, то есть новое решение, это библиотека inetaf/netaddr [3] (конечно, не исключено, что это результат теории вывода). И инициируйте вопросы и предложения в вопросах Go.

Расс Кокс инициировал обсуждение нового предложения « предложение: net/netaddr: добавить новый тип IP-адреса, пакет netaddr (обсуждение) [4] », которое было принято и внесено в новые функции Go1.18.
процесс восстановления
Каждое рассмотрение новой net/netip
библиотеки Брэд подробно объяснил в статье.
Из-за нехватки места мы поделимся двумя из них.Заинтересованные партнеры могут прочитать аналитическую часть исходного текста.
комбинация типов интерфейса
С точки зрения сопоставимости интерфейс Go фактически поддерживает сравнение, то есть его можно использовать в качестве ключа карты для сравнения ==
операторов .
Реализована первая версия схемы следующим образом и разработаны новые netaddr.IP
типы :
type IP struct {
ipImpl
}
type ipImpl interface {
is4() bool
is6() bool
String() string
}
type v4Addr [4]byte
type v6Addr [16]byte
type v6AddrZone struct {
v6Addr
zone string
}
Вышеприведенный код добавляет в структуру IP интерфейс ipImpl, который может не только поддерживать сравнение, но и не подвергаться воздействию внешнего мира (непрозрачный тип) и может поддерживать IPv6.
Новая проблема заключается в том, что, хотя он и меньше, чем нативная сеть, он все же не достигает цели, и у него все еще есть недостаток выделения памяти в куче.
Нераспределенные 24 байта
Если вы продолжите использовать интерфейс, вы не сможете решить основную цель (цель Брэда — 24 байта).
Поскольку интерфейс занимает 16 байт, оставшиеся 8 байт можно использовать, и следует разместить следующие вещи:
-
Семейство адресов (v4, v6 или ни то, ни другое, например: ноль для IP), требуется как минимум 2 бита. -
Информация о зоне IPv6.
Тоже надо сравнивать, явно интерфейс не реализовать, т.к. информация адрес+зона считает количество байт, а на дисплей не хватает.
Нет возможности сделать это формально и явно, Брэд додумался использовать метод упаковки:
type IP struct {
addr [16]byte
zoneAndFamily uint64
}
Но это означает, что необходимо вычислить количество цифр в поле zoneAndFamily, а затем вставить соответствующее значение, но это может быть не слишком сложно.
В конце концов Брэд придумал способ использовать указатели:
type IP struct {
addr [16]byte
zoneAndFamily *T
}
Затем определите три соответствующих значения Sentinel для применения:
var (
z0 *intern.Value // 表示零值。
z4 = new(intern.Value) // 表示 IPv4 的哨位值
z6noz = new(intern.Value) // 表示 IPv6 的哨位值(没有 zone)。
)
Это фиксирует тип IP на 24 байта.
Подвести итог
Эта библиотека сетевых адресов обычно используется реже. Но Брэд Фитцпатрик приложил много усилий и исследований, чтобы дойти до конца.
В дополнение к функциям библиотеки есть много точек технической оптимизации, достойных нашего изучения и ссылки.Если вас интересует глубокая оптимизация, вы можете прочитать: https://tailscale.com/blog/netaddr-new- ip-type-for-go/ [ 5]
Новая библиотека net/netip, представленная в этой статье, появится как новая функция в Go1.18, и все желающие могут учиться и общаться вместе :)
использованная литература
netaddr.IP: новый тип IP-адреса для Go: https://tailscale.com/blog/netaddr-new-ip-type-for-go/
[2]
инетаф/нетаддр: https://github.com/inetaf/netaddr
[3]
инетаф/нетаддр: https://github.com/inetaf/netaddr
[4]
предложение: net/netaddr: добавить новый тип IP-адреса, пакет netaddr): https://github.com/golang/go/discussions/47323
[5]
https://tailscale.com/blog/netaddr-new-ip-type-for-go/: https://tailscale.com/blog/netaddr-new-ip-type-for-go/#wgcfg
Подписывайтесь на Fried Fish, чтобы узнавать новости и информацию из первых рук👇

Здравствуйте, я Цзяньюй. Я опубликовал бестселлер Go "Путешествие программирования на языке Go", а затем получил награду GOP (самый самоуверенный эксперт в области Go). Нажмите на синее слово, чтобы увидеть мой книгоиздательский путь .
Ежедневно делитесь высококачественными статьями, публикуйте Go-интервью, опыт работы, архитектурный дизайн и присоединяйтесь к WeChat, чтобы привлечь читателей в группу обмена для общения со всеми!