25.1. 프로그램언어 고(Go)의 TCP 기반 통신

프로그램언어 고(Go)의 TCP 서버 구축

Go언어로 TCP 서버를 구축하는 방법을 최대한 친절하고 쉽게 설명드리겠습니다.


package main

import (
    "bufio"
    "fmt"
    "net"
)

func main() {

    // TCP 서버를 8080 포트로 listen
    ln, err := net.Listen("tcp", ":8080")
    if err != nil {
        panic(err)
    }

    // 클라이언트 접속을 기다림
    for {
        conn, err := ln.Accept()
        if err != nil {
            continue
        }

        // 접속한 클라이언트와 연결을 유지
        go handleConnection(conn) 
    }
}

func handleConnection(conn net.Conn) {
    // 클라이언트로부터 데이터를 읽기 위한 bufio 선언
    reader := bufio.NewReader(conn)  

    for {
        // 클라이언트 데이터 수신
        message, err := reader.ReadString('\n')
        if err != nil {
            fmt.Println(err)
            return 
        }

        fmt.Print("Message Received:", string(message))
        
        // 클라이언트로 메시지 재전송
        conn.Write([]byte(message + "\n"))   
    }
    conn.Close()  
}

위의 코드에서 TCP 서버를 listen하고 클라이언트의 접속을 수락하는 과정을 설명드리겠습니다.

먼저 net 패키지의 Listen() 함수로 8080 포트에서 TCP 서버를 listen합니다.

Listen() 함수에서 error가 발생하면 panic() 함수로 에러를 처리합니다.

그 다음 for문으로 무한루프를 돌며 클라이언트의 접속을 기다립니다.

net.Accept() 함수에서 클라이언트의 접속이 수락되면 해당 커넥션을 리턴받습니다.

접속한 클라이언트와의 통신을 유지하기 위해 handleConnection() 고루틴을 실행합니다.

handleConnection() 함수 내에서는 클라이언트로부터 데이터를 읽기 위해 bufio 패키지의 NewReader() 함수로 리더를 생성합니다.

for문으로 무한루프를 돌면서 클라이언트로부터 데이터를 계속 읽습니다.

ReadString() 함수로 개행문자(\n)까지的数据를 수신하고 클라이언트로 메시지를 재전송합니다.

이렇게 Go언어의 TCP 서버를 구현할 수 있습니다.

위 설명이 도움이 되셨기를 바랍니다.

프로그램언어 고(Go)에서의 TCP 클라이언트 구성

Go언어에서 TCP 클라이언트를 구성하는 방법은 다음과 같습니다.


package main

import (
    "bufio"
    "fmt"
    "net"
    "os"
)

func main() {

    // TCP 서버 주소 지정
    serverAddr := "127.0.0.1:8080"

    // TCP 서버 연결
    conn, err := net.Dial("tcp", serverAddr)
    if err != nil {
        panic(err)
    }

    // 연결 성공 메시지 출력
    fmt.Println("Connected to server")

    // 사용자 입력을 받기 위한 리더 생성
    reader := bufio.NewReader(os.Stdin)

    // 서버와 데이터 송수신
    for {
        // 사용자 입력 받기
        fmt.Print("Text to send: ")
        text, _ := reader.ReadString('\n')

        // 서버로 데이터 보내기
        fmt.Fprintf(conn, text+"\n")

        // 서버로부터 데이터 받기
        message, _ := bufio.NewReader(conn).ReadString('\n')
        fmt.Print("Message from server: "+message)
    }
}

주요 기능은 다음과 같습니다.

1. net.Dial() 함수를 사용하여 TCP 서버에 연결합니다.
2. bufio.NewReader()를 사용하여 사용자 입력을 받습니다.
3. conn을 통해 서버로 데이터를 보냅니다.
4. conn을 통해 서버로부터 데이터를 받습니다.

이와 같이 Go언어의 표준 네트워크 라이브러리를 사용하여 간단하게 TCP 클라이언트를 구성할 수 있습니다.

conn과 같은 네트워크 연결은 사용 후 Close() 함수로 닫아주는 것이 좋습니다.

예제는 간단한 에코 서버 통신입니다. 실제 프로덕션에서는 보다 체계적인 데이터 처리가 필요할 것입니다.

설명 드렸습니다. Go언어 TCP 클라이언트에 대한 추가 질문은 답변 요청 부탁드립니다.

프로그램언어 고(Go)의 TCP 패킷 조작

고(Go)언어의 TCP 패킷 조작에 대해 설명 드리겠습니다. TCP 패킷은 전송 계층의 통신 프로토콜인 TCP(Transmission Control Protocol)를 사용하여 전달되는 데이터 단위입니다.

고(Go)언어에서는 net 패키지를 사용하여 TCP 패킷을 조작할 수 있습니다. 주요한 기능은 다음과 같습니다.


// TCP 패킷 생성
tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:8080")

// TCP 커넥션 생성 
conn, err := net.DialTCP("tcp", nil, tcpAddr)

// TCP 패킷 보내기
conn.Write([]byte("Hello World!"))

// TCP 패킷 받기  
buf := make([]byte, 512)
conn.Read(buf)

net.DialTCP() 함수를 사용하여 TCP 커넥션을 생성할 수 있습니다. 그리고 conn.Write() 메서드로 패킷을 보내고, conn.Read() 메서드로 패킷을 받을 수 있습니다.

즉, TCP 스트림 상에서 데이터를 주고받을 때 사용하는 패킷들을 고(Go)언어에서 직접 생성하고 해석할 수 있다는 의미입니다.

더 자세한 예제 코드는 다음과 같습니다.


package main

import (
    "fmt"
    "net"
)

func main() {

    // TCP 서버 만들기
    server, err := net.Listen("tcp", ":8080")
    if err != nil {
        panic(err)
    }
    defer server.Close()

    // 클라이언트 연결 대기
    conn, err := server.Accept() 
    if err != nil {
        panic(err)  
    }

    // 클라이언트가 보낸 데이터 받기 
    buf := make([]byte, 512)
    _, err = conn.Read(buf)
    if err != nil {
        panic(err)
    }

    // 데이터 화면 출력
    recvData := string(buf)
    fmt.Println(recvData)

    // 서버에서 클라이언트로 데이터 보내기
    _, err = conn.Write([]byte("Hello Client"))
    if err != nil {
        panic(err)
    }
}

이 예제는 TCP 서버를 열어서 클라이언트의 연결을 받고, 클라이언트가 보낸 데이터를 수신한 후 서버에서 응답 데이터를 다시 보내는 기본 통신 과정을 보여줍니다.

conn.Read()와 conn.Write() 메서드를 사용하여 TCP 패킷들을 직접 주고받는 것을 확인할 수 있습니다. 필요에 따라 이를 확장하여 다양한 TCP 기반의 네트워크 애플리케이션을 개발할 수 있겠습니다.

지금까지 고(Go)언어의 TCP 패킷 조작 기능에 대해 간략히 설명해드렸습니다. 보다 자세한 사항이나 예제가 필요하시다면 문의 주시면 최대한 도와드리도록 하겠습니다.

프로그램언어 고(Go)에서의 TCP 연결 관리

프로그램언어 고(Go)에서 TCP 연결을 관리하는 방법은 다음과 같습니다.


// TCP 서버를 시작합니다 
ln, err := net.Listen("tcp", ":8080")
if err != nil {
    log.Fatal(err)
}

// 클라이언트 연결을 수락합니다
conn, err := ln.Accept() 
if err != nil {
    log.Fatal(err)
}

// 클라이언트와 데이터를 주고받습니다
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
    log.Fatal(err)  
}

n, err = conn.Write([]byte("Hello client")) 
if err != nil {
    log.Fatal(err)
}

TCP 서버를 시작하고 클라이언트의 연결을 받아들이는 부분이 중요합니다.

net.Listen() 함수로 특정 포트에서 수신 대기하고, ln.Accept()로 클라이언트 연결을 수락할 수 있습니다.

그리고 반환된 conn 객체를 사용하여 클라이언트와 데이터를 주고받을 수 있죠.

conn.Read(), conn.Write() 메서드를 이용하는 것입니다.

TCP 연결을 지속적으로 유지하거나 여러 클라이언트를 처리해야 한다면 고루틴을 사용하여 병렬처리가 가능합니다.


for {
    // 클라이언트 연결 수락 
    conn, err := ln.Accept()
    if err != nil {
        continue
    }
    
    // 고루틴에서 해당 클라이언트 처리
    go handleClient(conn) 
}

func handleClient(conn net.Conn) {
    defer conn.Close()
    
    // 클라이언트와 데이터 주고받기 
    buf := make([]byte, 1024)
    for {
        n, err := conn.Read(buf)
        if err != nil {
            return
        }
        
        n, err = conn.Write(buf[:n])
        if err != nil {
            return
        }
    }
}

이렇게 고루틴을 사용하면 클라이언트마다 병렬적으로 처리가 가능합니다.

TCP 연결 관리는 서버 or 클라이언트 구조에 따라 조금씩 다르겠지만, 기본적인 구조와 사용법은 위와 같습니다.

궁금한 점이 있으시면 언제든 질문 주세요.

프로그램언어 고(Go)의 TCP 통신 보안

Go 언어의 TCP 통신 보안은 중요한 문제입니다. Go 언어는 기본적으로 TLS(Transport Layer Security)를 지원하여 TCP 통신의 안전성을 보장합니다.


// TLS 설정
tlsConfig := &tls.Config{
   MinVersion:               tls.VersionTLS12,
   PreferServerCipherSuites: true,
}

// TLS listenner 생성  
listener, err := tls.Listen("tcp", ":443", tlsConfig)
if err != nil {
    log.Fatal(err)
}

// TLS 연결 수락
conn, err := listener.Accept()
if err != nil {
    log.Println(err)
    return 
}

위 코드는 Go 언어로 TLS를 설정하고, TLS 기반의 listener를 생성한 뒤 클라이언트의 TLS 연결을 수락하는 과정을 보여줍니다.

중요한 점은 tls.Config를 통해 안전한 TLS 버전(TLS 1.2)과 암호 제품군을 설정한다는 것입니다.

또한 서버의 인증서와 개인키를 지정하면 클라이언트는 서버의 정체성을 확인할 수 있습니다.


cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
if err != nil {
    log.Fatal(err) 
}

tlsConfig := &tls.Config{
    Certificates: []tls.Certificate{cert},
}

위 코드는 서버 인증서와 개인키를 tls.Config에 지정하는 과정을 보여줍니다.

이렇게 하면 클라이언트는 서버의 정체성을 확인할 수 있기 때문에 중간자(Man-in-the-Middle) 공격을 방지할 수 있습니다.

추가로 mutual TLS Authentication을 구현할 수도 있습니다. 서버만이 아니라 클라이언트도 인증서를 제공하여 양측이 서로를 인증하는 방식입니다.

이를 통해 TCP 통신의 보안성을 한층 더 높일 수 있습니다.

Leave a Comment