una tipos sirve significa rastrear que publicas para golang dirección direcciones direccion como arrays go network-programming ip slice

arrays - tipos - que significa ip



Manera eficiente de verificar el IP en un segmento de direcciones IP en Golang (2)

Estoy desarrollando una aplicación de red en Golang. Tengo una porción de direcciones IP. Cada vez que se recibe una solicitud, uso net.LookupIP(host) para averiguar la dirección IP del host que devuelve una porción de net.IP ¿Cuál es el mejor enfoque para comparar estos?

Por cierto, en Python tenemos una estructura de datos set que hace que la pregunta anterior sea tan fácil de resolver, pero ¿qué hay de Go?


Puede usar func (ip IP) Equal(x IP) bool del paquete de net :

Igual reporta si ip y x son la misma dirección IP. Una dirección IPv4 y esa misma dirección en formato IPv6 se consideran iguales.

Como esta muestra de trabajo:

package main import ( "fmt" "net" ) func main() { ip := net.ParseIP("127.0.0.1") ips, err := net.LookupIP("localhost") if err != nil { panic(err) } for _, v := range ips { if v.Equal(ip) { fmt.Println(v) } } }


Con un "conjunto"

Construyendo nuestro set

No hay ningún tipo de Set incorporado en Go, pero puedes usar elegantemente un map[Type]bool como conjunto, por ejemplo:

// Create a set with 2 values in it: [1, 2] m := map[int]bool{1: true, 2: true} // Test an element: fmt.Println(m[1]) // true fmt.Println(m[3]) // false // Set an element: m[3] = true fmt.Println(m[3]) // true // Delete an element: delete(m, 1) fmt.Println(m[1]) // false

Nota: explotamos el hecho de que si una clave no está en el mapa, la indexación del mapa da como resultado el valor cero para el tipo de valor, que es false en caso de bool , indicando correctamente que el elemento no está en el mapa (conjunto) .

Pruébalo en el patio de juegos Go .

Nota n. ° 2 : hay algunos trucos para hacer que el código para manejar un mapa como un conjunto sea más corto, puedes verificarlos en esta respuesta: Comprueba si un valor está en una lista .

Usando net.IP en el conjunto

Ahora solo necesitamos un tipo que represente net.IP que se pueda usar como tipo de clave en un mapa (consulte esta pregunta sobre qué constituye un tipo de clave de mapa: ¿Cómo puedo evitar que se use un tipo como clave de mapa? ).

Lamentablemente, net.IP no califica porque es un segmento:

type IP []byte

Y las rebanadas no son comparables. Consulte esta pregunta para obtener más información: Hash con la tecla como tipo de matriz y esto: ¿Por qué las matrices en Go?

Una forma fácil es convertirlo en un valor de string canónico y listo. Para esto, simplemente podemos convertir los bytes de la IP en una string hexadecimal. Pero una dirección IPv4 puede presentarse como IPv6, por lo que primero debemos convertirla a IPv6:

func Key(ip net.IP) string { return hex.EncodeToString(ip.To16()) }

Nota: los bytes de una dirección IP pueden no ser una string codificada UTF-8 válida (que es cómo Go almacena string s en la memoria), pero string valores de string en Go representan secuencias de bytes arbitrarias, por lo que lo siguiente también funciona, es mucho más simple y mucho más eficiente:

func Key(ip net.IP) string { return string(ip.To16()) // Simple []byte => string conversion }

Podemos usar cadenas de IP como las claves. Rellene su mapa con direcciones IP para comprobar:

// Populate forbidden IPs: forbIPs := map[string]bool{ Key(ip1): true, Key(ip2): true, } // Now check a single IP: ipToCheck := ... if forbIPs[Key(ipToCheck)] { fmt.Println("Forbidden!") } else { fmt.Println("Allowed.") }

Si tiene varias direcciones IP para verificar (como las devuelve net.LookupIP() ), se trata de un ciclo único:

ips, err := net.LookupIP(host) // Check err for _, ip := range ips { if forbIPs[Key(ip)] { // FORBIDDEN! } }

Tipo de clave alternativa

Tenga en cuenta que, como se mencionó anteriormente, las divisiones no son comparables, pero las matrices sí. Entonces, también podríamos usar una matriz como clave. Así es como podría verse:

func Key(ip net.IP) (a [16]byte) { copy(a[:], ip) return } // And the IP set: forbIPs := map[[16]byte]bool{ // ... }

Alternativas

Rebanada ordenada

Alternativamente, podríamos simplemente almacenar las direcciones IP prohibidas en un segmento []net.IP , y mantenerlo ordenado . Si está ordenado, podemos usar la búsqueda binaria para encontrar una dirección IP (biblioteca estándar sort.Search() ).

Sí, la búsqueda binaria tiene complejidad O(log2(n)) comparación con la complejidad O(1) de la solución de mapa (hash) anterior. Pero esta alternativa tiene otro profesional:

La enumeración de direcciones IP individuales no siempre es práctica. A veces (a menudo) es más fácil enumerar rangos de IP. La primera solución no es factible para manejar rangos de IP, pero esta solución puede ser: puede encontrar rangos que cubren una dirección IP también en el tiempo O(log2(n)) .