net
Go 言語の net 標準ライブラリは非常に強力なライブラリで、ネットワーク通信、IP アドレス、DNS 解決、TCP/UDP プロトコル、HTTP プロトコルなどの一般的なタスクを処理する機能を提供します。Go 言語自体の並行性特性により、Go はネットワーク IO を処理する際に非常に簡潔で効率的です。
アドレス解決
Go はネットワークアドレスを解決するための 4 つの関数を提供します。以下で順に説明します。
MAC アドレス
シグネチャ
go
func ParseMAC(s string) (hw HardwareAddr, err error)例
go
package main
import (
"fmt"
"net"
)
func main() {
hw, err := net.ParseMAC("00:1A:2B:3C:4D:5E")
if err != nil {
panic(err)
}
fmt.Println(hw)
}CIDR
シグネチャ
go
func ParseCIDR(s string) (IP, *IPNet, error)例
go
package main
import (
"fmt"
"log"
"net"
)
func main() {
ipv4Addr, ipv4Net, err := net.ParseCIDR("192.0.2.1/24")
if err != nil {
log.Fatal(err)
}
fmt.Println(ipv4Addr)
fmt.Println(ipv4Net)
}IP アドレス
IP アドレスは ipv4、ipv6 の解決をサポートします。関数シグネチャは以下の通りです。
go
func ResolveIPAddr(network, address string) (*IPAddr, error)使用例は以下の通りです。
go
package main
import (
"fmt"
"net"
)
func main() {
ipv4Addr, err := net.ResolveIPAddr("ip4", "192.168.2.1")
if err != nil {
panic(err)
}
fmt.Println(ipv4Addr)
ipv6Addr, err := net.ResolveIPAddr("ip6", "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
if err != nil {
panic(err)
}
fmt.Println(ipv6Addr)
}TCP アドレス
TCP アドレスは tcp4、tcp6 をサポートします。シグネチャは以下の通りです。
go
func ResolveTCPAddr(network, address string) (*TCPAddr, error)使用例は以下の通りです。
go
package main
import (
"fmt"
"net"
)
func main() {
tcp4Addr, err := net.ResolveTCPAddr("tcp4", "0.0.0.0:2020")
if err != nil {
panic(err)
}
fmt.Println(tcp4Addr)
tcp6Addr, err := net.ResolveTCPAddr("tcp6", "[::1]:8080")
if err != nil {
panic(err)
}
fmt.Println(tcp6Addr)
}UDP アドレス
UDP アドレスは udp4、udp6 をサポートします。シグネチャは以下の通りです。
go
func ResolveUDPAddr(network, address string) (*UDPAddr, error)使用例は以下の通りです。
go
package main
import (
"fmt"
"net"
)
func main() {
udp4Addr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:2020")
if err != nil {
panic(err)
}
fmt.Println(udp4Addr)
udp6Addr, err := net.ResolveUDPAddr("udp6", "[::1]:8080")
if err != nil {
panic(err)
}
fmt.Println(udp6Addr)
}Unix アドレス
Unix アドレスは unix、unixgram、unixpacket をサポートします。シグネチャは以下の通りです。
go
func ResolveUnixAddr(network, address string) (*UnixAddr, error)使用例は以下の通りです。
go
package main
import (
"fmt"
"net"
)
func main() {
unixAddr, err := net.ResolveUnixAddr("unix", "/tmp/mysocket")
if err != nil {
panic(err)
}
fmt.Println(unixAddr)
}DNS
Go は DNS 照会に使用する多くの関数も提供します。以下はドメイン名の IP アドレスを解決する例です。
go
package main
import (
"fmt"
"net"
)
func main() {
addrs, err := net.LookupHost("github.com")
if err != nil {
panic(err)
}
fmt.Println(addrs)
}レコード値を照会します。
go
package main
import (
"fmt"
"net"
)
func main() {
mxs, err := net.LookupMX("github.com")
if err != nil {
panic(err)
}
fmt.Println(mxs)
}ネットワークプログラミング
TCP プログラミングのロジックは非常に単純です。クライアントの場合:
- 接続を確立
- データを送信または読み取り
- 終了
サーバーの場合:
- アドレスをリッスン
- 接続を取得
- 新しいゴルーチンを作成して接続を処理
以下は簡単な例です。クライアントコード
go
package main
import (
"net"
)
func main() {
// 接続を確立
conn, err := net.Dial("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer conn.Close()
// データを送信
for i := range 10 {
_, err := conn.Write([]byte{'a' + byte(i)})
if err != nil {
panic(err)
}
}
}サーバーコード
go
package main
import (
"errors"
"fmt"
"io"
"net"
"sync"
)
func main() {
// アドレスをリッスン
listener, err := net.Listen("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer listener.Close()
var wg sync.WaitGroup
for {
// 接続が確立されるのをブロックして待機
conn, err := listener.Accept()
if err != nil {
panic(err)
}
// 新しいゴルーチンを開始して接続を非同期に処理
wg.Add(1)
go func() {
defer wg.Done()
buf := make([]byte, 4096)
for {
// 接続からデータを読み取り
n, err := conn.Read(buf)
if errors.Is(err, io.EOF) {
break
} else if err != nil {
panic(err)
}
data := string(buf[:n])
fmt.Println(data)
}
}()
}
wg.Wait()
}クライアントはデータを送信し、サーバーはデータを受信します。この例は非常に単純で、サーバーは新しい接続を確立する際に、新しいゴルーチンを開始するだけで処理でき、ブロックする必要はありません。UDP の実装方法も概ね同様です。
