net
Die net Standardbibliothek von Go ist eine sehr mächtige Bibliothek. Sie bietet Funktionen für Netzwerkkommunikation, IP-Adressen, DNS-Auflösung, TCP/UDP-Protokolle, HTTP-Protokoll und andere häufige Aufgaben. Dank der eingebauten Nebenläufigkeitsfunktionen von Go ist die Handhabung von Netzwerk-IO sehr prägnant und effizient.
Adressauflösung
Go bietet vier Funktionen zur Auflösung von Netzwerkadressen. Diese werden im Folgenden erklärt.
MAC-Adresse
Signatur
func ParseMAC(s string) (hw HardwareAddr, err error)Beispiel
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
Signatur
func ParseCIDR(s string) (IP, *IPNet, error)Beispiel
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-Adresse
IP-Adresse unterstützt die Auflösung von IPv4 und IPv6. Die Funktionssignatur lautet:
func ResolveIPAddr(network, address string) (*IPAddr, error)Verwendungsbeispiel:
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-Adresse
TCP-Adresse unterstützt tcp4 und tcp6. Die Signatur lautet:
func ResolveTCPAddr(network, address string) (*TCPAddr, error)Verwendungsbeispiel:
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-Adresse
UDP-Adresse unterstützt udp4 und udp6. Die Signatur lautet:
func ResolveUDPAddr(network, address string) (*UDPAddr, error)Verwendungsbeispiel:
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-Adresse
Unix-Adresse unterstützt unix, unixgram und unixpacket. Die Signatur lautet:
func ResolveUnixAddr(network, address string) (*UnixAddr, error)Verwendungsbeispiel:
package main
import (
"fmt"
"net"
)
func main() {
unixAddr, err := net.ResolveUnixAddr("unix", "/tmp/mysocket")
if err != nil {
panic(err)
}
fmt.Println(unixAddr)
}DNS
Go bietet viele Funktionen für DNS-Abfragen. Das folgende Beispiel zeigt die Auflösung der IP-Adresse eines Domainnamens:
package main
import (
"fmt"
"net"
)
func main() {
addrs, err := net.LookupHost("github.com")
if err != nil {
panic(err)
}
fmt.Println(addrs)
}Datensatz abfragen:
package main
import (
"fmt"
"net"
)
func main() {
mxs, err := net.LookupMX("github.com")
if err != nil {
panic(err)
}
fmt.Println(mxs)
}Netzwerkprogrammierung
Die Logik der TCP-Programmierung ist sehr einfach. Für den Client bedeutet das:
- Verbindung herstellen
- Daten senden oder lesen
- Beenden
Für den Server bedeutet das:
- Adresse überwachen
- Verbindung annehmen
- Eine neue Goroutine starten, um die Verbindung zu verarbeiten
Hier ist ein einfaches Beispiel. Client-Code:
package main
import (
"net"
)
func main() {
// Verbindung herstellen
conn, err := net.Dial("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer conn.Close()
// Daten senden
for i := range 10 {
_, err := conn.Write([]byte{'a' + byte(i)})
if err != nil {
panic(err)
}
}
}Server-Code:
package main
import (
"errors"
"fmt"
"io"
"net"
"sync"
)
func main() {
// Adresse überwachen
listener, err := net.Listen("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer listener.Close()
var wg sync.WaitGroup
for {
// Blockierend auf nächste Verbindung warten
conn, err := listener.Accept()
if err != nil {
panic(err)
}
// Neue Goroutine starten um die Verbindung asynchron zu verarbeiten
wg.Add(1)
go func() {
defer wg.Done()
buf := make([]byte, 4096)
for {
// Daten aus der Verbindung lesen
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()
}Der Client sendet Daten und der Server empfängt sie. Dieses Beispiel ist sehr einfach. Wenn der Server eine neue Verbindung erhält, startet er einfach eine neue Goroutine zur Verarbeitung, ohne zu blockieren. UDP funktioniert im Wesentlichen ähnlich.
