net
Go 언어의 net 표준 라이브러리는 매우 강력한 라이브러리로, 네트워크 통신, IP 주소, DNS 해석, TCP/UDP 프로토콜, HTTP 프로토콜 등 일반적인 작업 처리 기능을 제공합니다. Go 언어 자체의 동시성 특성 덕분에 Go 는 네트워크 IO 를 처리할 때 매우 간결하고 효율적입니다.
주소 해석
Go 는 네트워크 주소를 해석하는 네 가지 함수를 제공합니다. 아래에서 하나씩 설명하겠습니다.
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 도 대체로 유사하게 작성합니다.
