Go 言語の net/netip
パッケージの詳細な説明: Addr
type
皆さん、こんにちは!今日は、net/netip
型に焦点を当てて、Go 言語の Addr
パッケージについて詳しく説明します。 Go のネットワーク コードを使用している場合は、古い net.IP
タイプに遭遇したことがあるかもしれません。これは私たちにとって有益ですが、最新のネットワーク コードには適さないといういくつかの欠点があります。 net/netip
パッケージ (Go 1.18 で導入) は、IP アドレスを処理するためのより強力かつ効率的な方法を提供します。
net/netip.Addr
を選ぶのですか? 詳細に入る前に、このタイプが存在する理由を理解しましょう。従来の net.IP
型は基本的にバイトのスライス ([]byte
) であり、次のことを意味します:
==
演算子は使用できません新しい Addr
タイプは、これらの問題をすべて解決します。これは値型 (内部構造) であり、不変であり、常に有効な IP アドレスを表します。もう防御的なプログラミングは必要ありません。
Addr
Addr
の作成と使用の基本を見てみましょう:
<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>
ParseAddr
の利点の 1 つは、非常に厳密であることです。奇妙な形式や無効なアドレスは受け入れられません。例:
<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>
Addr
方法Addr
で使用する主なメソッドを見てみましょう。それぞれの方法が役立つ例をいくつか紹介します。
<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>
プロのヒント: IPv4 にマップされた IPv6 アドレス (::ffff:192.0.2.1
など) を扱う場合は、Is4In6()
を使用して検出します。これは、プロトコルに依存しないコードを作成する場合に特に便利です。
Addr
タイプは、IP アドレスを分類するいくつかの方法を提供します。包括的な例を次に示します:
<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>
実践例: ループバック インターフェイスを除くすべてのインターフェイスにバインドする必要があるサービスを作成しているとします。
<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>
IPv6 を使用している場合は、最終的にゾーンに遭遇します。これらは主に、使用するネットワーク インターフェイスを指定するためにリンクローカル アドレスとともに使用されます:
<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>
これらすべてを実際の例にまとめてみましょう。これは、Web サービスに使用できる単純な IP フィルターです:
<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>
使用例:
<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>
net/netip.Addr
の優れた点の 1 つは、そのパフォーマンス機能です。値型なので:
net.IP
とは異なります)net.IP
と netip.Addr
をランダムに混合しないでください。これらの間で変換することは可能ですが、一貫性を保つために、コードベース全体で netip.Addr
を使用するようにしてください。 MustParseAddr
テストまたは初期化コードでは便利ですが、ユーザー入力を処理する運用コードでは ParseAddr
を使用することを推奨します。 WithZone
など) は、実際には新しいアドレスを返します。 この記事では、Addr
型の基本といくつかの高度な使用法について説明しますが、net/netip
パッケージにはさらに多くの内容が含まれています。次の記事では、IP アドレスとポート番号を組み合わせる AddrPort
について説明します。これはネットワーク プログラミングに非常に便利です。
それまではコーディングを楽しんでください!プロジェクトで net/netip.Addr
を使用してご質問がある場合は、お気軽にお問い合わせください。
以上がGo の net/netip アドレス タイプについて: 詳細の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。