무지개곰
article thumbnail
반응형

TCP 서버와 RPC 서버에 대하여 공부한 내용을 기록하려고 합니다. TCP 서버와 RPC 서버를 직접 생성해본적이 처음이라 완전하게 이해되지 않았지만 관련 내용을 공부할 때마다 참고하기 위하여 배운 내용을 정리해 두겠습니다.

잘못된 설명에 대한 조언 혹은 추가적인 설명은 항상 배우는 자세로 감사히 받겠습니다.

목차

TCP 서버

RPC 서버

느낀 점


TCP 서버

TCP 서버는 Transmission Control Protocol을 기반으로 클라이언트와의 네트워크 통신을 처리하는 서버 소프트웨어입니다.  TCP 서버에 대한 자세한 설명, 특징과 용도에 대하여 설명드리겠습니다.

TCP 서버란?

TCP 서버는 클라이언트-서버 모델에서 서버 역할을 하는 소프트웨어입니다. 이 서버는 클라이언트로부터 연결을 수락하고, 클라이언트와의 양방향 통신을 관리합니다. TCP 프로토콜을 사용하여 데이터의 안정적인 전송을 보장하며, 서버-클라이언트 간의 신뢰성 있는 통신을 제공합니다.

TCP 서버의 특징

TCP 서버는 어떠한 특징을 가지고 있는지 알아보겠습니다.

연결 지향성 : TCP는 연결을 설정하고, 데이터를 안정적으로 전송한 후 연결을 종료하는 연결 지향 프로토콜입니다.

신뢰성 : 데이터를 손실 없이 안전하게 전송하며, 수신 측에서 데이터의 순서를 보장합니다.

양방향 통신 : 클라이언트와 서버는 양방향 통신을 할 수 있으며, 데이터를 주고받을 수 있습니다.

포트 사용 : TCP 서버는 특정 포트에서 클라이언트의 연결을 수락합니다.

TCP 서버의 용도

모든 용도를 이해한 것은 아니지만 웹 서버, 이메일 서버, 채팅 서버 등 웹 페이지 구현에 필요한 서버들이 있다는 정도로 이해하였습니다. 추후에 개발을 하며 참고하면 좋을 것 같습니다.

웹 서버 : 웹 페이지, 이미지, 파일 등을 클라이언트에게 제공하는 데 사용됩니다.

이메일 서버 : 전자 메일을 수신하고 전송하는 서버로 사용됩니다.

채팅 서버 : 실시간 채팅 애플리케이션을 위한 서버로 사용됩니다.

게임 서버 : 멀티플레이어 게임을 지원하기 위한 서버로 사용됩니다.

데이터 베이스 서버 : 데이터베이스 연결을 관리하고 데이터를 응용 프로그램에 전달하는 데 사용됩니다.

TCP 서버 생성

package main

import (
	"fmt"
	"net"
)

func main() {
	listener, err := net.Listen("tcp", ":8080")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer listener.Close()

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("Error:", err)
			continue
		}

		go handleConnection(conn)
	}
}

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

	buffer := make([]byte, 1024)
	_, err := conn.Read(buffer)
	if err != nil {
		fmt.Println("Error reading:", err)
		return
	}

	// 데이터 처리 논리...
}

1. 'net.Listen("tcp", ":8080")' 함수 호출은 TCP 프로토콜을 사용하는 서버를 8080 포트에서 수신 대기 상태로 만듭니다. 만약 에러가 발생하면 에러를 출력하고 프로그램을 종료합니다.

2. 'defer listener.Close()'는 서버가 종료될 때 리스너를 닫습니다. 이것은 서버가 종료되기 전에 리스너를 명시적으로 닫지 않아도 되도록 해줍니다.

3. 메인 루프에서 'listener.Accept()'호출은 클라이언트의 연결을 기다립니다. 클라이언트가 연결 요청을 보내면 이 함수가 반환하고, 연결이 수락됩니다. 에러가 발생하면 에러를 출력하고 계속 대기 상태를 유지합니다.

4. 연결이 수락되면 'handleConnection' 함수가 고루틴으로 실행됩니다. 각 클라이언트 연결에 대한 처리는 별도의 고루틴에서 이루어집니다.

5. 'handleConnection'함수는 클라이언트와의 통신을 처리합니다. 먼저 연결을 닫을 수 있도록 'defer conn.Close()'을 사용합니다.

6. byte슬라이스를 생성하여 클라이언트로부터 데이터를 읽어옵니다.


RPC 서버

RPC는 Remote Procedure Call의 약자로 RPC 서버는 분산 시스템에서 원격 프로시저 호출을 허용하는 서버입니다. RPC 서버에 대한 자세한 설명, 특징과 용도에 대하여 설명드리겠습니다.

RPC 서버란?

RPC 서버는 클라이언트와 서버 간의 함수 호출을 원격으로 수행하기 위한 프로그래밍 모텔입니다. 클라이언트는 마치 로컬 함수를 호출하는 것처럼 원격 서버의 함수를 호출하고, 서버에서 처리된 결과를 반환합니다. 이를 통해 분산 시스템에서 다른 프로세스나 시스템 간에 함수 호출을 쉽게 수행할 수 있습니다.

RPC 서버의 특징

RPC 서버는 다음과 같은 특징을 가지고 있습니다. 각 특징에 대하여 직접 프로그래밍을 해보아야 이해될 것 같습니다. 더 많은 공부를 통하여 프로그래밍을 하게 되면 꼭 기록해 두겠습니다.

함수 호출 추상화 : RPC 서버는 클라이언트와 서버 간의 함수 호출을 추상화하고, 원격 함수 호출을 로컬 함수 호출처럼 사용할 수 있도록 합니다.

데이터 직렬화 : 함수 호출과 함께 데이터를 직렬화하여 네트워크를 통해 전송하고, 역직렬화하여 함수 인자와 반환 값을 처리합니다.

프로토콜 추상화 : 서버와 클라이언트 간의 통신에 사용되는 프로토콜을 추상화하고, 다양한 프로토콜을 지원합니다.

클라이언트-서버 모델 : RPC 서버는 클라이언트와 서버 간의 통신 모델을 사용하여 함수 호출을 관리합니다.

RPC 서버의 용도

RPC 서버는 다음과 같은 용도로 사용됩니다.

분산 시스템 통합 : 다양한 서비스 및 서버 간에 함수 호출을 통합하고 분산 시스템을 구축하는 데 사용됩니다.

서비스 제공 : 클라이언트에 대한 서비스를 제공하기 위해 사용됩니다. 클라이언트가 원격 서버의 함수를 호출하여 서비스를 이용할 수 있습니다.

비즈니스 로직 분리 : 클라이언트와 서버 간에 비즈니스 로직을 분리하고, 서버 측에서 로직을 실행하는 데 사용됩니다.

효율적인 데이터 공유 : 데이터 공유 및 동기화를 위해 서버 간에 함수 호출을 사용하여 데이터 공유를 효율적으로 관리합니다.

RPC 서버 생성

package main

import (
	"fmt"
	"net"
	"net/rpc"
)

type MyService struct{}

func (s *MyService) Multiply(args *Args, reply *int) error {
	*reply = args.A * args.B
	return nil
}

type Args struct {
	A, B int
}

func main() {
	myService := new(MyService)
	rpc.Register(myService)

	listener, err := net.Listen("tcp", ":8080")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer listener.Close()

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("Error:", err)
			continue
		}

		go rpc.ServeConn(conn)
	}
}

1. 'MyService' 구조체는 RPC 서비스를 정의하기 위한 것입니다.

'Multiply' 메서드를 가지고 있으며, 클라이언트에서 요청이 들어오면 이 메서드가 실행됩니다. 'Args' 구조체를 통해 두 정수를 전달받고, 그 값을 곱한 결과를 클라이언트에게 반환합니다.

2. 'Args' 구조체는 RPC 메서드에 전달되는 매개변수를 정의하는 구조체입니다.

3. 'rpc.Register(myService)''MyService'를 RPC 서버에 등록합니다. 이를 통해 클라이언트에서 'MyService'의 메서드를 호출할 수 있게 됩니다.

4. 'net.Listen("tcp", ":8080")'은 TCP 프로토콜을 사용하는 서버를 8080 포트에서 수신 대기 상태로 만듭니다. 만약 에러가 발생하면 에러를 출력하고 프로그램을 종료합니다.

5. 'defer listener.Close()'를 사용하여 서버가 종료될 때 리스너를 닫습니다. 이것은 서버가 종료되기 전에 리스너를 명시적으로 닫지 않아도 되도록 해줍니다.

6. 메인 루프에서 'listener.Accept()' 호출은 클라이언트의 연결을 기다립니다. 클라이언트가 연결 요청을 보내면 이 함수가 반환하고, 연결이 수락됩니다. 에러가 발생하면 에러를 출력하고 계속 대기 상태를 유지합니다.

7. 연결이 수락되면 'rpc.ServeConn(conn)'함수가 고루틴으로 실행됩니다. 이 함수는 클라이언트와의 RPC 통신을 처리합니다.


느낀 점

지금까지 서버는 Nodejs의 express를 이용하여 RESTful API 통신만 해보았기에 생소한 서버였습니다. 각 서버를 어떻게 활용하는지 공부가 더 필요하다고 느꼈고 많은 연습을 통하여 각 용도에 맞는 서버를 만들어보고 싶다는 동기부여가 되었던 공부였습니다.

책에서도 이후 내용에서 깊이 있게 프레임워크를 다룰 때, 이 내용이 실제 운영을 위한 마이크로 서비스를 구축하는 데 어떻게 활용될 수 있는지 살펴본다고 나와있습니다.

정말 무엇인가 배우고 있다는 느낌과 성장에 대한 의지가 가득해지는 공부를 한다는 것이 너무 즐겁습니다.

반응형
profile

무지개곰

@무지개곰

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!