Go 언어에서 네트워크 통신의 타임아웃 설정 방법

네트워크 프로그래밍에서는 연결 또는 데이터 전송이 지연되는 경우를 방지하기 위해 타임아웃 설정이 필수적입니다. 이 문서에서는 Go 언어로 네트워크 연결 및 읽기/쓰기 타임아웃을 설정하는 방법에 대해 설명합니다.

1. 타임아웃 설정

1.1 연결 타임아웃

DialTimeout 함수는 네트워크 연결 시 타임아웃을 설정하는 데 사용됩니다.

func DialTimeout(network, address string, timeout time.Duration) (Conn, error)

위 함수에서 timeout 매개변수는 연결이 완료되기까지 기다리는 최대 시간을 지정합니다. 설정된 시간을 초과하면 타임아웃 오류가 반환됩니다.

1.2 읽기/쓰기 타임아웃

Conn 인터페이스에는 읽기와 쓰기 동작에 대한 타임아웃 설정 메서드가 포함되어 있습니다.

type Conn interface {
    SetDeadline(t time.Time) error
    SetReadDeadline(t time.Time) error
    SetWriteDeadline(t time.Time) error
}

각 메서드는 특정 시간 이후의 작업을 제한하며, 해당 시간 이후에도 작업이 완료되지 않으면 타임아웃 오류가 발생합니다. 매번 새로운 시간을 설정해야 하며, 이를 갱신하지 않을 경우 계속해서 타임아웃 상태에 있을 수 있습니다.


2. 예제 코드

2.1 서버(SERVER)

아래 서버 코드는 클라이언트와 연결 후 데이터를 주고받습니다. 쓰기 작업 전에 일부 지연(3초)을 추가하여 타임아웃 테스트를 수행합니다.

package main

import (
	"log"
	"net"
	"time"
)

func main() {
	addr := "0.0.0.0:8080"

	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		log.Fatalf("ResolveTCPAddr 실패: %s", addr)
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		log.Fatalf("리스닝 실패: %s", addr)
	}
	log.Println("서버 시작:", addr)

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println("연결 수락 실패:", err)
			continue
		}

		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()

	message := []byte("안녕하세요! 저는 서버입니다.")

	for {
		time.Sleep(3 * time.Second) // 3초 대기
		n, err := conn.Write(message)
		if err != nil {
			log.Println("데이터 전송 실패:", err)
			break
		}
		log.Println("전송 완료:", n, "바이트")
	}
}

2.2 클라이언트(CLIENT)

클라이언트는 연결 시 3초의 타임아웃을 설정하고, 읽기 작업마다 타임아웃을 재설정합니다.

package main

import (
	"log"
	"net"
	"os"
	"time"
)

func main() {
	connTimeout := 3 * time.Second
	conn, err := net.DialTimeout("tcp", "127.0.0.1:8080", connTimeout)
	if err != nil {
		log.Println("연결 실패:", err)
		os.Exit(1)
	}
	defer conn.Close()

	readTimeout := 2 * time.Second
	buffer := make([]byte, 512)

	for {
		deadline := time.Now().Add(readTimeout)
		err = conn.SetReadDeadline(deadline)
		if err != nil {
			log.Println("타임아웃 설정 실패:", err)
		}

		n, err := conn.Read(buffer)
		if err != nil {
			log.Println("읽기 실패:", err)
		} else {
			log.Printf("읽은 데이터: %d 바이트, 내용: %s", n, string(buffer[:n]))
		}
	}
}

3. 실행 결과

클라이언트는 2초의 읽기 타임아웃으로 설정되어 있으며, 서버가 3초마다 데이터를 보내므로 일부 읽기 작업에서 타임아웃이 발생합니다.

2023/10/10 14:18:19 읽기 실패: read tcp 127.0.0.1:51718->127.0.0.1:8080: i/o timeout
2023/10/10 14:18:23 읽은 데이터: 28 바이트, 내용: 안녕하세요! 저는 서버입니다.
2023/10/10 14:18:25 읽기 실패: read tcp 127.0.0.1:51718->127.0.0.1:8080: i/o timeout

타임아웃 설정을 통해 네트워크 지연 문제를 효과적으로 관리할 수 있습니다.

태그: Golang Networking timeouts

6월 2일 19:31에 게시됨