Heim > Backend-Entwicklung > Golang > Den Netz-/Netip-Addr-Typ von Go verstehen: Ein tiefer Einblick

Den Netz-/Netip-Addr-Typ von Go verstehen: Ein tiefer Einblick

Susan Sarandon
Freigeben: 2025-01-11 10:55:42
Original
941 Leute haben es durchsucht

Understanding Go

Detaillierte Erläuterung des

-Pakets von net/netipGo-Sprache: AddrTyp

Hallo zusammen! Heute werden wir uns mit dem net/netip-Paket der Go-Sprache befassen und uns dabei auf den Typ Addr konzentrieren. Wenn Sie mit dem Netzwerkcode von Go gearbeitet haben, sind Sie möglicherweise auf den alten Typ net.IP gestoßen. Obwohl es uns gute Dienste geleistet hat, weist es einige Nachteile auf, die es für modernen Netzwerkcode weniger geeignet machen. Das net/netip-Paket (eingeführt in Go 1.18) bietet uns eine leistungsfähigere und effizientere Möglichkeit, IP-Adressen zu verarbeiten.

Warum wählennet/netip.Addr?

Bevor wir auf die Details eingehen, wollen wir verstehen, warum es diesen Typ gibt. Der traditionelle net.IP-Typ ist im Grunde ein Byte-Slice ([]byte), was bedeutet:

  • Variable
  • Erfordert Heap-Zuweisung
  • Kann einen ungültigen Status enthalten
  • Der ==-Operator kann nicht zum Vergleich verwendet werden

Der neue Addr Typ löst all diese Probleme. Es ist ein Werttyp (interne Struktur), unveränderlich und stellt immer eine gültige IP-Adresse dar. Keine defensive Programmierung mehr!

Loslegen SieAddr

Sehen wir uns die Grundlagen der Erstellung und Verwendung von Addr an:

<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>
Nach dem Login kopieren
Ein Vorteil von

ParseAddr ist, dass es sehr streng ist. Es werden keine seltsamen Formate oder ungültigen Adressen akzeptiert. Zum Beispiel:

<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>
Nach dem Login kopieren

Besprechen Sie ausführlich die AddrMethode

Lassen Sie uns die wichtigsten Methoden erkunden, die Sie mit Addr verwenden werden. Ich werde einige praktische Beispiele dafür geben, wo jede Methode nützlich ist.

Ist das IPv4 oder 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>
Nach dem Login kopieren

Profi-Tipp: Wenn Sie mit IPv4-zugeordneten IPv6-Adressen (z. B. ::ffff:192.0.2.1) arbeiten, verwenden Sie Is4In6(), um diese zu erkennen. Dies ist besonders nützlich, wenn Sie protokollunabhängigen Code schreiben.

Adressklassifizierungsmethode

Der Typ

Addr bietet mehrere Möglichkeiten zur Klassifizierung von IP-Adressen. Hier ist ein umfassendes Beispiel:

<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>
Nach dem Login kopieren

Praxisbeispiel: Nehmen wir an, Sie schreiben einen Dienst, der an alle Schnittstellen außer der Loopback-Schnittstelle gebunden werden muss:

<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>
Nach dem Login kopieren

Zone verwenden (IPv6-Bereichs-ID)

Wenn Sie IPv6 verwenden, werden Sie irgendwann auf Zonen stoßen. Sie werden hauptsächlich mit Link-Local-Adressen verwendet, um anzugeben, welche Netzwerkschnittstelle verwendet werden soll:

<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>
Nach dem Login kopieren

Praktische Anwendung: IP-Adressfilter

Lassen Sie uns das alles in einem praktischen Beispiel zusammenfassen. Dies ist ein einfacher IP-Filter, der für Webdienste verwendet werden kann:

<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>
Nach dem Login kopieren

Anwendungsbeispiel:

<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>
Nach dem Login kopieren

Leistungshinweise

Eines der großartigen Dinge an

net/netip.Addr sind seine Leistungsmerkmale. Da es sich um einen Werttyp handelt:

  • Grundlegende Operationen ohne Heap-Zuweisung
  • Effiziente Vergleichsvorgänge
  • Ein Nullwert ist ungültig (im Gegensatz zu net.IP, wo ein Nullwert gültig sein kann)

Einige häufige Fallstricke und Tricks

  1. Mischen Sie net.IP und netip.Addr nicht willkürlich. Aus Gründen der Konsistenz sollten Sie jedoch versuchen, netip.Addr in Ihrer gesamten Codebasis beizubehalten.
  2. Beachten Sie die Fläche im Vergleich Zusätzlich zur Fläche gelten zwei identische Adressen als unterschiedliche Adressen.
  3. Mit Vorsicht verwenden MustParseAddr Obwohl dies im Test- oder Initialisierungscode praktisch ist, bevorzugen Sie ParseAddr im Produktionscode, der Benutzereingaben verarbeitet.
  4. Denken Sie daran, dass es unveränderlich ist. Alle Methoden, die scheinbar die Adresse ändern (z. B. WithZone), geben tatsächlich eine neue Adresse zurück.

Was kommt als nächstes?

Dieser Artikel behandelt die Grundlagen und einige fortgeschrittene Verwendungsmöglichkeiten der Addr-Typen, aber im net/netip-Paket gibt es noch viel mehr zu entdecken. Im nächsten Artikel schauen wir uns AddrPort an, das eine IP-Adresse mit einer Portnummer kombiniert – sehr nützlich für die Netzwerkprogrammierung.

Bis dahin viel Spaß beim Programmieren! Wenn Sie Fragen zur Verwendung von net/netip.Addr in Ihrem Projekt haben, können Sie sich gerne an uns wenden.

Das obige ist der detaillierte Inhalt vonDen Netz-/Netip-Addr-Typ von Go verstehen: Ein tiefer Einblick. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage