Maison >développement back-end >Golang >Comprendre le type d'adresse Go's net/netip : une plongée en profondeur

Comprendre le type d'adresse Go's net/netip : une plongée en profondeur

Susan Sarandon
Susan Sarandonoriginal
2025-01-11 10:55:42949parcourir

Understanding Go

Explication détaillée du package

Go Language : net/netiptypeAddr

Bonjour à tous ! Aujourd'hui, nous allons approfondir le package

du langage Go, en nous concentrant sur le type net/netip. Si vous avez travaillé avec le code réseau de Go, vous avez peut-être rencontré l'ancien type Addr. Bien qu'il nous ait bien servi, il présente certains inconvénients qui le rendent moins adapté au code réseau moderne. Le package net.IP (introduit dans Go 1.18) nous offre un moyen plus puissant et efficace de gérer les adresses IP. net/netip

Pourquoi choisir

? net/netip.Addr

Avant d’entrer dans les détails, comprenons pourquoi ce type existe. Le type traditionnel

est essentiellement une tranche d'octets (net.IP), ce qui signifie : []byte

    Variable
  • Nécessite une allocation de tas
  • Peut contenir un statut invalide
  • Impossible d'utiliser l'opérateur
  • pour la comparaison==
Le nouveau type

résout tous ces problèmes. C'est un type valeur (structure interne), immuable, et représente toujours une adresse IP valide. Fini la programmation défensive ! Addr

Commencez

Addr

Regardons les bases de la création et de l'utilisation de

 : Addr

Un avantage de
<code class="language-go">package main

import (
    "fmt"
    "net/netip"
)

func main() {
    // 从字符串创建Addr
    addr, err := netip.ParseAddr("192.168.1.1")
    if err != nil {
        panic(err)
    }

    // 如果你绝对确定输入
    addr2 := netip.MustParseAddr("2001:db8::1")

    fmt.Printf("IPv4: %v\nIPv6: %v\n", addr, addr2)
}</code>

est qu'il est très strict. Il n'acceptera pas les formats étranges ou les adresses invalides. Par exemple : ParseAddr

<code class="language-go">// 这些将会失败
_, err1 := netip.ParseAddr("256.1.2.3")        // 无效的IPv4八位字节
_, err2 := netip.ParseAddr("2001:db8::1::2")   // 无效的IPv6(双冒号)
_, err3 := netip.ParseAddr("192.168.1.1/24")   // Addr不允许CIDR表示法</code>
Discuter en profondeur de la

méthodeAddr

Explorons les méthodes clés que vous utiliserez avec

. Je vais partager quelques exemples pratiques montrant où chaque méthode est utile. Addr

Est-ce IPv4 ou IPv6 ?

<code class="language-go">func checkAddressType(addr netip.Addr) {
    if addr.Is4() {
        fmt.Println("这是IPv4")
        // 你可以在这里安全地使用As4()
        bytes := addr.As4()
        fmt.Printf("作为字节:%v\n", bytes)
    } else if addr.Is6() {
        fmt.Println("这是IPv6")
        // 你可以在这里安全地使用As16()
        bytes := addr.As16()
        fmt.Printf("作为字节:%v\n", bytes)
    }
}</code>
Conseil de pro : lorsque vous traitez des adresses IPv6 mappées IPv4 (telles que

), utilisez ::ffff:192.0.2.1 pour les détecter. Ceci est particulièrement utile lors de l’écriture de code indépendant du protocole. Is4In6()

Méthode de classification des adresses

Le type

propose plusieurs façons de classer les adresses IP. Voici un exemple complet : Addr

<code class="language-go">func classifyAddress(addr netip.Addr) {
    checks := []struct {
        name string
        fn   func() bool
    }{
        {"IsGlobalUnicast", addr.IsGlobalUnicast},
        {"IsPrivate", addr.IsPrivate},
        {"IsLoopback", addr.IsLoopback},
        {"IsMulticast", addr.IsMulticast},
        {"IsLinkLocalUnicast", addr.IsLinkLocalUnicast},
        {"IsLinkLocalMulticast", addr.IsLinkLocalMulticast},
        {"IsInterfaceLocalMulticast", addr.IsInterfaceLocalMulticast},
        {"IsUnspecified", addr.IsUnspecified},
    }

    for _, check := range checks {
        if check.fn() {
            fmt.Printf("地址是 %s\n", check.name)
        }
    }
}</code>
Exemple pratique : disons que vous écrivez un service qui doit se lier à toutes les interfaces à l'exception de l'interface de bouclage :

<code class="language-go">func getBindableAddresses(addrs []netip.Addr) []netip.Addr {
    var bindable []netip.Addr
    for _, addr := range addrs {
        if !addr.IsLoopback() && !addr.IsLinkLocalUnicast() {
            bindable = append(bindable, addr)
        }
    }
    return bindable
}</code>
Utiliser la zone (ID de portée IPv6)

Si vous utilisez IPv6, vous finirez par rencontrer des zones. Ils sont principalement utilisés avec des adresses lien-local pour spécifier quelle interface réseau utiliser :

<code class="language-go">func handleZones() {
    // 创建一个带有区域的地址
    addr := netip.MustParseAddr("fe80::1%eth0")

    // 获取区域
    zone := addr.Zone()
    fmt.Printf("区域:%s\n", zone)

    // 比较带有区域的地址
    addr1 := netip.MustParseAddr("fe80::1%eth0")
    addr2 := netip.MustParseAddr("fe80::1%eth1")

    // 由于区域不同,这些是不同的地址
    fmt.Printf("相同的地址?%v\n", addr1 == addr2)  // false

    // WithZone创建一个具有不同区域的新地址
    addr3 := addr1.WithZone("eth2")
    fmt.Printf("新的区域:%s\n", addr3.Zone())
}</code>
Application pratique : Filtre d'adresse IP

Rassemblons tout cela dans un exemple pratique. Il s'agit d'un simple filtre IP qui peut être utilisé pour les services Web :

<code class="language-go">type IPFilter struct {
    allowed []netip.Addr
    denied  []netip.Addr
}

func NewIPFilter(allowed, denied []string) (*IPFilter, error) {
    f := &IPFilter{}

    // 解析允许的地址
    for _, a := range allowed {
        addr, err := netip.ParseAddr(a)
        if err != nil {
            return nil, fmt.Errorf("无效的允许地址 %s: %w", a, err)
        }
        f.allowed = append(f.allowed, addr)
    }

    // 解析拒绝的地址
    for _, d := range denied {
        addr, err := netip.ParseAddr(d)
        if err != nil {
            return nil, fmt.Errorf("无效的拒绝地址 %s: %w", d, err)
        }
        f.denied = append(f.denied, addr)
    }

    return f, nil
}

func (f *IPFilter) IsAllowed(ip string) bool {
    addr, err := netip.ParseAddr(ip)
    if err != nil {
        return false
    }

    // 首先检查拒绝列表
    for _, denied := range f.denied {
        if addr == denied {
            return false
        }
    }

    // 如果没有指定允许的地址,则允许所有未被拒绝的地址
    if len(f.allowed) == 0 {
        return true
    }

    // 检查允许列表
    for _, allowed := range f.allowed {
        if addr == allowed {
            return true
        }
    }

    return false
}</code>
Exemple d'utilisation :

<code class="language-go">func main() {
    filter, err := NewIPFilter(
        []string{"192.168.1.100", "10.0.0.1"},
        []string{"192.168.1.50"},
    )
    if err != nil {
        panic(err)
    }

    tests := []string{
        "192.168.1.100",  // 允许
        "192.168.1.50",   // 拒绝
        "192.168.1.200",  // 不在任何列表中
    }

    for _, ip := range tests {
        fmt.Printf("%s 允许?%v\n", ip, filter.IsAllowed(ip))
    }
}</code>
Notes de performances

L'un des avantages de

réside dans ses fonctionnalités de performance. Puisqu'il s'agit d'un type valeur : net/netip.Addr

  • Opérations de base sans allocation de tas
  • Opérations de comparaison efficaces
  • Une valeur nulle n'est pas valide (contrairement à net.IP, où une valeur zéro peut être valide)

Quelques pièges et astuces courants

  1. Ne mélangez pas net.IP et netip.Addr au hasard Bien qu'il soit possible de convertir entre eux, par souci de cohérence, essayez de vous en tenir à netip.Addr dans toute votre base de code.
  2. Notez la zone dans la comparaison En plus de la zone, deux adresses identiques sont considérées comme des adresses différentes.
  3. À utiliser avec prudence MustParseAddr Bien que pratique dans le code de test ou d'initialisation, préférez ParseAddr dans le code de production qui gère les entrées de l'utilisateur.
  4. N'oubliez pas qu'il est immuable. Toutes les méthodes qui semblent modifier l'adresse (telles que WithZone) renvoient en fait une nouvelle adresse.

Quelle est la prochaine étape ?

Cet article couvre les bases et une utilisation avancée des types Addr, mais il y a bien plus à explorer dans le package net/netip. Dans le prochain article, nous examinerons AddrPort, qui combine une adresse IP avec un numéro de port - très utile pour la programmation réseau.

En attendant, bon codage ! Si vous avez des questions sur l'utilisation de net/netip.Addr dans votre projet, n'hésitez pas à nous contacter.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn