net
La biblioteca estándar net de Go es muy poderosa. Proporciona funciones para manejar tareas comunes como comunicación de red, direcciones IP, resolución DNS, protocolos TCP/UDP, protocolo HTTP, etc. Debido a las características de concurrencia del lenguaje Go, el manejo de E/S de red es muy conciso y eficiente.
Análisis de direcciones
Go proporciona cuatro funciones para analizar direcciones de red. A continuación se explican una por una.
Dirección MAC
Firma
func ParseMAC(s string) (hw HardwareAddr, err error)Ejemplo
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)Ejemplo
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)
}Dirección IP
La dirección IP admite el análisis de ipv4 e ipv6. La firma de la función es la siguiente
func ResolveIPAddr(network, address string) (*IPAddr, error)El ejemplo de uso es el siguiente
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)
}Dirección TCP
La dirección TCP admite tcp4 y tcp6. La firma es la siguiente
func ResolveTCPAddr(network, address string) (*TCPAddr, error)El ejemplo de uso es el siguiente
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)
}Dirección UDP
La dirección UDP admite udp4 y udp6. La firma es la siguiente
func ResolveUDPAddr(network, address string) (*UDPAddr, error)El ejemplo de uso es el siguiente
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)
}Dirección Unix
La dirección Unix admite unix, unixgram y unixpacket. La firma es la siguiente
func ResolveUnixAddr(network, address string) (*UnixAddr, error)El ejemplo de uso es el siguiente
package main
import (
"fmt"
"net"
)
func main() {
unixAddr, err := net.ResolveUnixAddr("unix", "/tmp/mysocket")
if err != nil {
panic(err)
}
fmt.Println(unixAddr)
}DNS
Go también proporciona muchas funciones para consultas DNS. A continuación se muestra un ejemplo de análisis de la dirección IP de un nombre de dominio
package main
import (
"fmt"
"net"
)
func main() {
addrs, err := net.LookupHost("github.com")
if err != nil {
panic(err)
}
fmt.Println(addrs)
}Consultar valores de registro MX
package main
import (
"fmt"
"net"
)
func main() {
mxs, err := net.LookupMX("github.com")
if err != nil {
panic(err)
}
fmt.Println(mxs)
}Programación de red
La lógica de programación TCP es muy simple. Para el cliente es
- Establecer conexión
- Enviar datos o leer datos
- Salir
Para el servidor es
- Escuchar dirección
- Obtener conexión
- Crear una nueva goroutine para manejar la conexión
A continuación se muestra un ejemplo simple, código del cliente
package main
import (
"net"
)
func main() {
// Establecer conexión
conn, err := net.Dial("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer conn.Close()
// Enviar datos
for i := range 10 {
_, err := conn.Write([]byte{'a' + byte(i)})
if err != nil {
panic(err)
}
}
}Código del servidor
package main
import (
"errors"
"fmt"
"io"
"net"
"sync"
)
func main() {
// Escuchar dirección
listener, err := net.Listen("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer listener.Close()
var wg sync.WaitGroup
for {
// Bloquear esperando que se establezca la siguiente conexión
conn, err := listener.Accept()
if err != nil {
panic(err)
}
// Iniciar una nueva goroutine para manejar la conexión de forma asíncrona
wg.Add(1)
go func() {
defer wg.Done()
buf := make([]byte, 4096)
for {
// Leer datos de la conexión
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()
}El cliente envía datos y el servidor recibe datos. Este ejemplo es muy simple. Cuando el servidor establece una nueva conexión, solo necesita iniciar una nueva goroutine para manejarla sin bloquear. La escritura de UDP es generalmente similar.
