Hola a todos, soy pescaito frito.
Cuando escribí este artículo, era el primer día del nuevo año y originalmente quería decir que Go1.18 se lanzaría este mes. Pero, buen chico, se lanzó Go1.18 beta2, y el funcionario le dijo a la comunidad que Go1.18 se retrasará hasta marzo, gugugu...
Como se muestra abajo:

Por lo tanto, todavía tenemos que seguir aprendiendo nuevas funciones. Hoy, Jianyu se combinará con " netaddr.IP: un nuevo tipo de dirección IP para Go [1] " de Brad Fitzpatrick para mostrarle el motivo de la nueva biblioteca de red de Go1.18 net/ punta de red
antecedentes
Renuncia el gran jefe
Brad Fitzpatrick, que estaba en el equipo de desarrollo original de Go, trabajó en el equipo de Go de 2010 a 2020 y cambiará de empresa en 2021.
El siguiente tuit:

Razón para irse: He estado haciendo lo mismo durante demasiado tiempo, me aburro y no quiero quedar atrapado en una situación cómoda.
Ahora parece que cambié a Tailscale para hacer el trabajo relacionado con WireGuard, y tengo que lidiar con bibliotecas de red con frecuencia.
Nace la demanda
Tailscale escrito por Big Brother es esencialmente una aplicación de red. Para manejar la red y escrito en Go, involucrará la biblioteca estándar net
:
-
Se utiliza en un único tipo de IP net.IP
. -
utilizado en la representación de la red net.IPNet
.
Código de muestra:
import (
"fmt"
"net"
)
func main() {
fmt.Println(net.IPv4(8, 8, 8, 8))
}
Resultado de salida:
8.8.8.8
Cuando Brad Fitzpatrick realmente lo escribió y usó, descubrió que hay muchos problemas con el tipo de biblioteca estándar de red, que es muy difícil de usar.
cual es el problema ahora
Brad Fitzpatrick enumeró los problemas de la biblioteca estándar net.IP directamente en el artículo, con argumentos completos.
Un total de 7 preguntas principales:
-
es mutable. net.IP
El tipo subyacente de es[]byte
, lo que significa que cualquier cosa que le pases puede cambiarlo. -
No es comparable. Debido a que los sectores en Go no son comparables, esto significa net.IP
que==
comparaciones de los operadores de Go no son compatibles y no se pueden usar como claves de mapa. -
Tiene dos tipos de direcciones IP, que pueden resultar molestos de usar net.IP
o de elegir.net.IPAddr
-
Es enorme. Go net.IP
contiene 2 partes, un encabezado de segmento de 24 bytes y una dirección IP de 4/6 bytes. Si es así,net.IPAddr
también se . -
Asignará memoria en el montón. El paquete de red de Go está distribuido por todas partes, lo que pone más trabajo en el GC. -
No es analizable. Al analizar la IP desde el formato de cadena, el tipo de IP de Go no puede distinguir entre las direcciones IPv6 asignadas a IPv4 y las direcciones IPv4. -
Es un tipo transparente, net.IP
definido como:type IP []byte
, es parte de su API pública y no se puede cambiar.
Brad también mencionó que algunos de los diseños se hicieron a principios de año, cuando no tenían experiencia o no estaban bien pensados.
Ahora está limitado por la promesa de compatibilidad con Go1 y no se puede cambiar (¿una espada de doble filo de garantías de compatibilidad?).
Esta es una versión real de "Comer tu propia comida para perros", por lo que en Tailscale reconstruyó otra rueda , inetaf/netaddr [2] , y quería contribuir con ella y meterla en la biblioteca estándar.
el futuro que quieres
La tabla de comparación es la siguiente:
característica | Antiguo esquema net.IP | Nuevo plan |
---|---|---|
Invariable | ❌, rebanada | ✅ |
comparable | ❌, rebanada | ✅ |
Pequeña huella de pie | ❌, 28~56 bytes | ✅, fijo 24 bytes |
no asignado en el montón | ❌ | ✅ |
Compatibilidad con IPv4 e IPv6 | ✅ | ✅ |
Diferenciar entre IPv4 e IPv6 | ❌ | ✅ |
Soporte de zona IPv6 | ❌ | ✅ |
tipo opaco | ❌ | ✅ |
Interoperar con la biblioteca estándar | ✅ | 🤷, necesita adaptar el método |
Lo que quiero es en realidad una demanda del negocio real de Brad, que es respaldar los 7 puntos mencionados anteriormente.
solución
progreso actual
El resultado de la realización, es decir, se realiza la nueva solución, es la librería inetaf/netaddr [3] (por supuesto, no se descarta que el resultado sea al revés). E iniciar temas y propuestas en temas Go.

Russ Cox inició la discusión de la nueva propuesta " propuesta: net/netaddr: agregar nuevo tipo de dirección IP, paquete netaddr (discusión) [4] ", que fue aceptada y entró en las nuevas características de Go1.18.
proceso de reconstrucción
Cada consideración de la nueva net/netip
biblioteca , Brad lo ha explicado en detalle en el artículo.
Por limitaciones de espacio, compartiremos dos de ellos, los socios interesados pueden leer la parte de análisis del texto original.
combinación de tipo de interfaz
En términos de comparabilidad, la interfaz de Go realmente admite la comparación, es decir, se puede usar como una clave de mapa para la comparación de ==
operadores .
Se implementa la primera versión del esquema de la siguiente manera y se diseñan nuevos netaddr.IP
tipos :
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
}
El código anterior agrega la interfaz ipImpl a la estructura IP, que no solo admite la comparación, sino que también no se expone al mundo exterior (tipo opaco) y puede admitir IPv6.
El nuevo problema es que, aunque es más pequeño que la red nativa, aún no logra el objetivo y aún tiene la desventaja de asignar en el montón.
24 bytes sin asignación
Si continúa utilizando la interfaz, no podrá resolver el objetivo subyacente (el objetivo de Brad es 24 bytes).
Debido a que la interfaz ocupa 16 bytes, los 8 bytes restantes se pueden usar y se deben colocar las siguientes cosas:
-
Familia de direcciones (v4, v6 o ninguna, por ejemplo: cero para IP), se requieren al menos 2 bits. -
Información de la zona IPv6.
También es necesario comparar, obviamente la interfaz no se puede realizar, porque la información de dirección + zona cuenta la cantidad de bytes y la visualización no es suficiente.
No hay forma de hacerlo formal y explícitamente, Brad pensó en usar el método de empaquetado:
type IP struct {
addr [16]byte
zoneAndFamily uint64
}
Pero hacer esto significa que se debe calcular la cantidad de dígitos en el campo zoneAndFamily, y luego se ingresa el valor correspondiente, pero puede que no sea demasiado problema.
Al final, a Brad se le ocurrió una forma de usar los punteros:
type IP struct {
addr [16]byte
zoneAndFamily *T
}
Luego defina tres valores centinela correspondientes para aplicar:
var (
z0 *intern.Value // 表示零值。
z4 = new(intern.Value) // 表示 IPv4 的哨位值
z6noz = new(intern.Value) // 表示 IPv6 的哨位值(没有 zone)。
)
Esto corrige el tipo de IP en 24 bytes.
Resumir
Esta biblioteca de direcciones de red generalmente se usa menos. Pero Brad Fitzpatrick puso mucha energía e investigación para llegar al final.
Además de las funciones de la biblioteca, hay muchos puntos de optimización técnica dignos de nuestro estudio y referencia. Si está interesado en la optimización en profundidad, puede leer: https://tailscale.com/blog/netaddr-new- ip-type-for-go/ [ 5]
La nueva biblioteca net/netip presentada en este artículo aparecerá como una nueva característica en Go1.18, y todos pueden aprender y comunicarse juntos :)
Referencias
netaddr.IP: un nuevo tipo de dirección IP para Go: https://tailscale.com/blog/netaddr-new-ip-type-for-go/
[2]
inetaf/netaddr: https://github.com/inetaf/netaddr
[3]
inetaf/netaddr: https://github.com/inetaf/netaddr
[4]
propuesta: net/netaddr: agregue un nuevo tipo de dirección IP, paquete 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
Siga a Fried Fish para obtener noticias y conocimientos de primera mano en la industria 👇

Hola, soy Jianyu. He publicado el libro más vendido de Go "Go Language Programming Journey", y luego gané el honor de GOP (el experto más obstinado en el campo de Go). Haga clic en la palabra azul para ver mi libro . camino editorial .
Comparta artículos de alta calidad a diario, genere entrevistas Go, experiencia laboral, diseño de arquitectura y únase a WeChat para atraer lectores al grupo de intercambio para comunicarse con todos.