Go Package : net
ChatGPT
mqtt 프로젝트를 진행하며, 별도의 TCP 소켓을 열어 메시지를 전달해야 하는 과제가 생겨
이전에 알아보다가 말았던 소켓을 적용하고자 한다.
Go에서 소켓 통신을 활용하기 위해서는 net 패키지를 활용해야 한다.
차근차근 정리해보자.

Go 언어에서 네트워크 통신을 수행하기 위해 net 패키지를 사용한다.
TCP, UDP, IP, HTTP 등 여러 네트워크 프로토콜을 구현하는 데 사용된다.net 패키지를 통해 소켓 생성, 서버-클라이언트 간 연결 관리, 데이터 송수신 등의 기능을 손쉽게 구현할 수 있다.
소켓 통신은 두 컴퓨터 또는 애플리케이션 간 양방향 통신을 제공하는 메커니즘이다.
IP 주소와 포트 번호를 사용해 네트워크 연결을 설정하며, 데이터 송수신 경로를 제공TCP/IP 같은 네트워크 프로토콜에서 소켓을 활용해 클라이언트와 서버 간 데이터 전송이 이루어짐
TCP(Transmission Control Protocol)는 연결 지향형 프로토콜로, 데이터 전송의 신뢰성과 순서 보장을 제공한다.
[TCP 소켓 통신 과정]
1. 서버 측
Accept) 하고 데이터를 송수신한다.2. 클라이언트 측
Dial 함수를 사용해 서버의 IP와 포트에 연결을 시도한다.
Go 언어의 net 패키지를 사용해 TCP 서버와 클라이언트를 구현할 수 있다.
import (
"bufio"
"fmt"
"log"
"net"
)
listener, err := net.Listen("tcp", "localhost:8080") // 서버 소켓 생성 및 포트 바인딩
// net.Listen(protocol, address) : tcp protocol, IP주소(localhost):포트(-p)
// listener 객체 : 클라이언트의 연결을 대기, 서버 소켓 역할 수행, Accept() 호출해 클라이언트의 연결 요청 수락
if err != nil {
// %v : 해당 값에 맞는 기본 형식으로 출력해주는 역할 [에러 메시지를 있는 그대로 깔끔하게 출력]
log.Fatalf("Failed to start server: %v", err)
}
defer listener.Close() // 함수 종료 시 리스너 자원 해제
// 클라이언트 연결 요청 대기
fmt.Println("Waiting for client connection...")
// 새로운 연결이 들어오면 해당 요청을 수락하고, 연결 객체 conn을 반환 (연결 실패 시 에러 반환)
conn, err := listener.Accept() // 클라이언트 연결 수락
if err != nil {
log.Fatalf("Failed to accept connection: %v", err)
}
defer conn.Close() // // 연결 종료 시 자원 해제
fmt.Println("Client connected!")
Listen: 서버 소켓을 생성하고 지정된 IP 주소와 포트에 바인딩Accept: 클라이언트가 연결 요청을 보내면 서버는 이를 수락서버는 여러 클라이언트와 동시에 통신하기 위해 다중 연결을 처리해야 할 수 있다.
Listen과Accept
Listen: 서버 소켓이 특정 포트에서 연결 요청을 받을 수 있도록 준비 상태로 만든다.
- 일반적으로 서버 소켓 초기화 후에 바로 호출하여 포트에서 대기
listen은 소켓 서버가 클라이언트의 연결 요청을 대기할 준비가 되었음을 나타냄- 이를 통해 서버는 특정 포트에서 들어오는 연결 요청을 수신할 수 있음
- 서버 소켓을 연결 대기 상태로 만들어 -> 특정 포트에 대한 클라이언트 요청을 받을 준비를 함
Accept: 들어오는 클라이언트 연결 요청을 실제로 수락하여, 클라이언트와의 통신을 시작할 수 있는 소켓을 반환한다.
- listen이 활성화된 포트로 들어온 클라이언트의 연결 요청을 수락하는 함수
- 클라이언트와 서버 간의 개별 연결을 처리하며, 성공적으로 연결되면 새로운 소켓을 반환하여 클라이언트와 직접 통신할 수 있게 함
- 클라이언트 요청을 수락하고, 서버가 클라이언트와 통신할 수 있도록 개별 연결 소켓을 생성
- 일반적으로
listen이후에 사용되며, 클라이언트가 연결을 요청할 때까지 블로킹 상태로 대기
// Dial을 사용해 서버에 연결
conn, err := net.Dial("tcp", "localhost:8080") // 서버와의 연결 시도
if err != nil {
log.Fatalf("Failed to connect to server: %v", err)
}
defer conn.Close()
fmt.Println("Connected to server!")
Dial: 클라이언트는 서버의 IP와 포트에 연결을 시도연결이 성공하면 클라이언트와 서버 간의 양방향 데이터 전송이 가능해진다.
서버와 클라이언트 간 데이터 송수신은 Write와 Read 함수를 통해 이루어진다.
1. 데이터 송신 (클라이언트 → 서버)
message := "Hello, Server!"
conn.Write([]byte(message)) // 서버로 데이터 전송
2. 데이터 수신 (서버에서 데이터 수신)
buffer := make([]byte, 1024) // 수신 버퍼 생성
n, err := conn.Read(buffer) // 클라이언트로부터 데이터 읽기
if err != nil {
log.Fatalf("Failed to read data: %v", err)
}
fmt.Printf("Received: %s\n", string(buffer[:n]))
Write: 연결된 소켓을 통해 데이터를 전송Read: 수신된 데이터를 버퍼에 저장하고, 읽은 바이트 수를 반환< 소켓 통신 활용의 이점 >
1. 실시간 통신: 서버와 클라이언트 간 빠르고 실시간으로 데이터를 주고받을 수 있다.
2. 양방향 연결: 클라이언트와 서버 모두 데이터 송수신이 가능하다.
3. 다중 연결 지원: 여러 클라이언트가 동시에 서버에 연결할 수 있다.
<TCP 소켓 통신과 Go의 net 패키지 활용 요약>
1. Go의 net 패키지는 소켓 통신을 간단하고 직관적으로 구현할 수 있게 해준다.
2. TCP 소켓 통신을 통해 연결의 신뢰성을 보장하며, MQTT와 같은 프로토콜과 병행하여 사용하면 다양한 통신 시나리오를 처리할 수 있다.
Go의
net패키지를 사용한 TCP 소켓 통신은 발행자와 구독자 간의 직접적인 메시지 전달에 유용하다.
내 프로젝트에서는 MQTT 브로커와 소켓을 조합해 메시지를 처리함으로써 효율적이고 신뢰성 있는 통신을 구현했다.