net
La libreria standard net di Go è molto potente, fornisce funzionalità per gestire comunicazioni di rete, indirizzi IP, risoluzione DNS, protocolli TCP/UDP, protocollo HTTP e altri compiti comuni. Grazie alle caratteristiche di concorrenza del linguaggio Go stesso, la gestione dell'IO di rete è molto concisa ed efficiente.
Risoluzione Indirizzi
Go fornisce quattro funzioni per analizzare indirizzi di rete, di seguito verranno spiegate una per una.
Indirizzo MAC
Firma
func ParseMAC(s string) (hw HardwareAddr, err error)Esempio
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
Firma
func ParseCIDR(s string) (IP, *IPNet, error)Esempio
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)
}Indirizzo IP
L'indirizzo IP supporta l'analisi di ipv4 e ipv6, la firma della funzione è la seguente
func ResolveIPAddr(network, address string) (*IPAddr, error)Esempio di utilizzo
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)
}Indirizzo TCP
L'indirizzo TCP supporta tcp4 e tcp6, la firma è la seguente
func ResolveTCPAddr(network, address string) (*TCPAddr, error)Esempio di utilizzo
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)
}Indirizzo UDP
L'indirizzo UDP supporta udp4 e udp6, la firma è la seguente
func ResolveUDPAddr(network, address string) (*UDPAddr, error)Esempio di utilizzo
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)
}Indirizzo Unix
L'indirizzo Unix supporta unix, unixgram, unixpacket, la firma è la seguente
func ResolveUnixAddr(network, address string) (*UnixAddr, error)Esempio di utilizzo
package main
import (
"fmt"
"net"
)
func main() {
unixAddr, err := net.ResolveUnixAddr("unix", "/tmp/mysocket")
if err != nil {
panic(err)
}
fmt.Println(unixAddr)
}DNS
Go fornisce anche molte funzioni per le query DNS, di seguito un esempio per analizzare l'indirizzo IP di un dominio
package main
import (
"fmt"
"net"
)
func main() {
addrs, err := net.LookupHost("github.com")
if err != nil {
panic(err)
}
fmt.Println(addrs)
}Interrogazione del record MX
package main
import (
"fmt"
"net"
)
func main() {
mxs, err := net.LookupMX("github.com")
if err != nil {
panic(err)
}
fmt.Println(mxs)
}Programmazione di Rete
La logica della programmazione tcp è molto semplice, per il client è
- Stabilire una connessione
- Inviare dati o leggere dati
- Uscire
Per il server è
- Ascoltare un indirizzo
- Ottenere la connessione
- Creare una nuova goroutine per gestire la connessione
Di seguito un esempio semplice, codice client
package main
import (
"net"
)
func main() {
// Stabilire una connessione
conn, err := net.Dial("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer conn.Close()
// Inviare dati
for i := range 10 {
_, err := conn.Write([]byte{'a' + byte(i)})
if err != nil {
panic(err)
}
}
}Codice server
package main
import (
"errors"
"fmt"
"io"
"net"
"sync"
)
func main() {
// Ascoltare un indirizzo
listener, err := net.Listen("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer listener.Close()
var wg sync.WaitGroup
for {
// Bloccare in attesa che la prossima connessione venga stabilita
conn, err := listener.Accept()
if err != nil {
panic(err)
}
// Avviare una nuova goroutine per gestire la connessione in modo asincrono
wg.Add(1)
go func() {
defer wg.Done()
buf := make([]byte, 4096)
for {
// Leggere dati dalla connessione
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()
}Il client invia dati, il server riceve dati, questo esempio è molto semplice, quando il server stabilisce una nuova connessione, basta avviare una nuova goroutine per gestirla, senza bloccare. La scrittura per UDP è fondamentalmente simile.
