Compare commits
5
Commits
d9b8fe6fde
...
daf90f07d9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daf90f07d9 | ||
|
|
5e6f7defd3 | ||
|
|
989529e8ba | ||
|
|
fc3a0d6b61 | ||
|
|
ed7f3cc4e4 |
+15
@@ -0,0 +1,15 @@
|
||||
.agents/
|
||||
.mam/
|
||||
.env
|
||||
.env.example
|
||||
AGENTS.md
|
||||
BOOTSTRAP.ko.md
|
||||
BOOTSTRAP.md
|
||||
MESSAGING.md
|
||||
remove.sh
|
||||
update.sh
|
||||
# Python virtual environment
|
||||
/.venv/
|
||||
|
||||
# Workspace-specific scripts
|
||||
/resume_all.sh
|
||||
@@ -1,4 +0,0 @@
|
||||
# 역할
|
||||
- 영어로 작성된 파일을 한국어로 번역
|
||||
- 번역된 표현에서 어색한 한국어 표현 수정 및 내용을 더욱 쉽게 이해할 수 있도록 내용 추가
|
||||
- 내용의 흐름은 바꾸지 말 것!
|
||||
@@ -1,67 +1,97 @@
|
||||
# JSON이란?
|
||||
# grpccanary: gRPC & Multi-Agent Interface Study Repository
|
||||
|
||||
`grpccanary`는 Go 언어를 활용한 데이터 직렬화(JSON) ➡️ 웹 서버(HTTP/Gin) ➡️ 원격 프로시저 호출(gRPC)의 기본기를 단계별로 익힐 수 있는 학습용 실습 저장소입니다.
|
||||
|
||||
# HTTP란?
|
||||
---
|
||||
|
||||
## `gin-gonic`을 이용한 http 서버 구현하기
|
||||
## 🎯 프로젝트 목적 및 배경
|
||||
|
||||
- 참고 자료
|
||||
본 프로젝트는 단순한 학습 튜토리얼을 넘어 아래와 같은 명확한 지향점을 가지고 관리되고 있습니다.
|
||||
|
||||
# gRPC란?
|
||||
1. **gRPC 기반 AIoT 멀티 에이전트(Multi-Agent) 인터페이스 개발을 위한 사전 학습**
|
||||
- 사물인터넷(IoT) 환경과 지능형 에이전트들이 유기적으로 데이터를 주고받는 분산 AIoT 시스템을 설계하기 위해서는 빠르고, 가벼우며, 타입 안전성이 보장되는 통신 프로토콜이 필수적입니다.
|
||||
- 본 프로젝트는 추후 개발할 **gRPC 기반 AIoT 멀티 에이전트 인터페이스 모듈**의 핵심 통신 기법을 선제적으로 실습하고 검증하기 위한 기술적 초석입니다.
|
||||
2. **후배 개발자 교육 및 공동 협업을 위한 가이드북**
|
||||
- 사용자 본인의 지식 내재화뿐만 아니라, 함께 개발에 참여할 후배 개발자들의 빠른 온보딩(Onboarding)과 체계적인 백엔드 통신 교육 자료 제공을 주요 목적으로 합니다.
|
||||
- 이를 위해 단계적 예제와 한국어 주석, 상세 이론 원고([docs/MANUSCRIPT.md](docs/MANUSCRIPT.md))를 꼼꼼하게 구성해 두고 있습니다.
|
||||
|
||||
이번 장에서는 Go 언어에서 gRPC를 어떻게 활용하는지 전반적으로 살펴보겠습니다.
|
||||
---
|
||||
|
||||
### gRPC 개요
|
||||
## 📂 프로젝트 구조 및 학습 단계 (3-Step Curriculum)
|
||||
|
||||
이 장은 Go 언어를 사용하여 gRPC를 다루는 방법을 설명합니다. gRPC는 'google Remote Procedure Calls'의 약자로, 구글이 개발한 RESTful 서비스의 대안입니다. gRPC의 가장 큰 장점은 REST와 JSON 메시지를 사용하는 방식보다 훨씬 빠르다는 점입니다.
|
||||
본 예제는 데이터의 형태를 정하는 기초적인 단계부터 고성능 네트워크 통신까지 난이도별로 3단계 학습을 진행할 수 있도록 구조화되어 있습니다.
|
||||
|
||||
또한, gRPC는 풍부한 도구들을 제공하여 gRPC 서비스용 클라이언트를 더 빠르고 쉽게 만들 수 있도록 돕습니다. 마지막으로, gRPC는 바이너리 데이터 형식을 사용하기 때문에 JSON 형식을 사용하는 RESTful 서비스보다 훨씬 가볍습니다.
|
||||
```
|
||||
grpccanary/
|
||||
├── README.md # 본 프로젝트 종합 소개 및 실행 가이드 (교육용)
|
||||
├── go.mod / go.sum # Go 모듈 의존성 정의 (Go 1.25.4+)
|
||||
├── protoapi.proto # gRPC 인터페이스 정의서 (IDL)
|
||||
├── protoapi/ # protoc로 컴파일 생성된 Go Stub 코드
|
||||
├── examples/
|
||||
│ ├── main.go # 학습 예제 통합 실행 진입점 (수동 전환)
|
||||
│ ├── jsonexample/ # [1단계] encoding/json 표준 직렬화 예제
|
||||
│ ├── httpentity/ # [2단계] Gin-gonic 기반 HTTP API 서버 (WIP)
|
||||
│ └── grpcentity/ # [3단계] gRPC 서비스 구현체 (서버/클라이언트 데모)
|
||||
└── docs/
|
||||
└── MANUSCRIPT.md # JSON, HTTP, gRPC에 대한 통합 상세 개념서
|
||||
```
|
||||
|
||||
gRPC 서버와 클라이언트를 개발하는 과정은 크게 세 단계로 나뉩니다. 첫째, 인터페이스 정의 언어(IDL) 파일을 생성합니다. 둘째, gRPC 서버를 개발합니다. 셋째, 개발된 gRPC 서버와 통신할 gRPC 클라이언트를 개발합니다.
|
||||
### 1단계: JSON 데이터 다루기 (`examples/jsonexample`)
|
||||
* Go 표준 라이브러리인 `encoding/json`을 활용하여 구조체(Struct)와 JSON 데이터 간의 마샬링(Serialization) 및 언마샬링(Deserialization) 기법을 학습합니다.
|
||||
|
||||
### 다룰 주제
|
||||
### 2단계: Gin 기반 HTTP 웹 서버 (`examples/httpentity`)
|
||||
* 대중적인 Go 웹 프레임워크 `gin-gonic`을 활용해 RESTful API 사양을 구축하는 방법을 이해합니다. (현재 주석 해제 후 실습하도록 설계된 Work-in-Progress 단계)
|
||||
|
||||
이번 장에서는 다음 주제들을 다룹니다:
|
||||
### 3단계: gRPC 통신 구현 (`examples/grpcentity`)
|
||||
* `.proto` 정의를 바탕으로 통신 스키마 계약을 강제하고, Go 언어로 gRPC 서버를 띄워 클라이언트가 날짜/시간, 무작위 비밀번호 및 정수 데이터를 실시간 원격 호출로 송수신하는 분산 통신 기초를 학습합니다.
|
||||
|
||||
- gRPC 소개
|
||||
- 인터페이스 정의 언어(IDL) 파일 정의
|
||||
- gRPC 서버 개발
|
||||
- gRPC 클라이언트 개발
|
||||
---
|
||||
|
||||
## gRPC 소개
|
||||
## 🤖 AI 에이전트 협업 인프라 (`multi-agent-mux`)
|
||||
|
||||
gRPC의 이점과 프로토콜 버퍼에 대해 자세히 알아보겠습니다.
|
||||
본 저장소에는 학습용 Go 소스코드 외에도 **AI 에이전트(Claude, Cline 등)가 TMUX와 MQTT 브로커를 활용해 스스로 개발하고 검수하는 다중 에이전트 협업 인프라**가 함께 내장되어 있습니다.
|
||||
|
||||
gRPC는 2015년 구글이 개발한 오픈소스 원격 프로시저 호출(RPC) 시스템입니다. HTTP/2를 기반으로 구축되어 서비스 개발을 용이하게 하며, 메시지 형식과 서비스 인터페이스를 정의하는 IDL(인터페이스 정의 언어)로 프로토콜 버퍼를 사용합니다.
|
||||
* **[AGENTS.md](AGENTS.md)**: AI 코딩 에이전트가 코드를 안전하게 수정할 수 있도록 제한하는 핵심 행동 지침(Surgical Changes, Simplicity First)입니다.
|
||||
* **`.agents/MULTI_AGENT_RULES.ko.md`**: 총괄 매니저, 개발 팀장, 리뷰어 팀장 간의 역할 정의 및 비동기 작업 결재 루프 프로토콜을 다룹니다.
|
||||
* **[resume_all.sh](resume_all.sh)**: 로컬에서 멈춘 작업 에이전트의 세션을 동적으로 한 번에 복원해 주는 자동화 복구 스크립트입니다. (로컬 전용 헬퍼로 Git 추적에서 제외됨)
|
||||
|
||||
gRPC 클라이언트와 서버는 서로 다른 프로그래밍 언어로 작성될 수 있습니다. 예를 들어, gRPC 서버가 Go 언어로 구현되었더라도 클라이언트는 Python으로 개발할 수 있습니다. 지원되는 프로그래밍 언어는 Python, Java, C++, C#, PHP, Ruby, Kotlin 등 다양합니다.
|
||||
---
|
||||
|
||||
### 장점
|
||||
## 🚀 실행 및 실습 방법
|
||||
|
||||
gRPC의 주요 장점은 다음과 같습니다:
|
||||
### 1. 사전 준비사항
|
||||
* Go 개발 환경이 필요합니다. (버전 **1.25.4 이상** 권장)
|
||||
* 리포지토리 루트에서 다음 명령어로 의존성 모듈을 설치합니다.
|
||||
```bash
|
||||
go mod download
|
||||
```
|
||||
|
||||
- **빠른 데이터 교환**: 바이너리 데이터 형식을 사용하여 일반 텍스트 기반 서비스보다 훨씬 빠르게 데이터를 교환합니다.
|
||||
- **간편한 개발 도구**: 풍부한 명령줄 도구들을 제공하여 개발 작업을 더욱 간단하고 신속하게 만듭니다.
|
||||
- **쉬운 서버/클라이언트 생성**: gRPC 서비스의 함수와 메시지를 정의한 후에는 RESTful 서비스보다 서버와 클라이언트를 더 쉽게 생성할 수 있습니다.
|
||||
- **스트리밍 지원**: 스트리밍 서비스에 효과적으로 활용될 수 있습니다.
|
||||
- **세부 사항 자동 처리**: 데이터 교환의 복잡한 세부 사항을 gRPC가 자동으로 처리해주므로 개발자가 신경 쓸 필요가 없습니다.
|
||||
### 2. 실습 예제 실행 방법 (진입점 전환)
|
||||
이 프로젝트는 교육적 목적을 위해 **하나의 `main.go` 파일 안에서 주석 처리를 통해 학습 단계를 수동 전환**하여 실행하도록 설계되어 있습니다.
|
||||
|
||||
> 참고: 이 장점 목록만 보고 gRPC가 모든 문제의 완벽한 해결책이라고 오해해서는 안 됩니다. 항상 현재 작업에 가장 적합한 도구나 기술을 선택하는 것이 중요합니다.
|
||||
1. **[examples/main.go](examples/main.go)** 파일을 엽니다.
|
||||
2. 아래와 같이 실행하고자 하는 예제의 주석을 해제하고 다른 예제는 주석 처리합니다.
|
||||
* *JSON 예제 실행 시*: `jsonexample.JsonParsingExample()` 활성화
|
||||
* *gRPC 예제 실행 시*: `grpcSample()` 활성화 (미사용 import 에러를 피하기 위해 `jsonexample` import는 주석 처리 필요)
|
||||
3. 루트 디렉토리에서 다음 명령어로 실행합니다:
|
||||
```bash
|
||||
go run ./examples
|
||||
```
|
||||
|
||||
다음 섹션에서는 gRPC 서비스의 핵심 기반 기술인 프로토콜 버퍼에 대해 자세히 알아보겠습니다.
|
||||
### 3. gRPC 예제 동작 흐름 및 기대 출력
|
||||
gRPC 예제 실행 시, 서버가 백업 고루틴으로 `:8080` 포트에 대기한 후 클라이언트가 접속하여 다음과 같은 출력을 냅니다.
|
||||
```text
|
||||
Serving requests...
|
||||
Client:
|
||||
Server Date and Time: 2026-07-12 20:00:00.123456789 +0900 KST
|
||||
Random Password: &c(D7f/G#s%d
|
||||
Random Integer 1: 42
|
||||
Random Integer 2: 87
|
||||
```
|
||||
|
||||
### 프로토콜 버퍼
|
||||
---
|
||||
|
||||
프로토콜 버퍼(Protobuf)는 구조화된 데이터를 효율적으로 직렬화하는 방법입니다. Protobuf는 IDL(인터페이스 정의 언어)의 일부로, 데이터 교환 시 바이너리 형식을 사용하기 때문에 일반 텍스트 기반 직렬화 형식보다 훨씬 적은 공간을 차지합니다. 하지만 데이터를 기계가 사용하고 사람이 읽을 수 있도록 하려면 각각 인코딩과 디코딩 과정이 필요합니다. Protobuf는 각 프로그래밍 언어에서 기본적으로 지원하는 데이터 타입으로 변환되는 자체 데이터 타입을 제공합니다.
|
||||
## 📚 추가 학습 리소스
|
||||
|
||||

|
||||
|
||||
일반적으로 IDL 파일은 모든 gRPC 서비스의 핵심입니다. 이는 데이터 교환 형식과 서비스 인터페이스를 정의하기 때문입니다. Protobuf 파일 없이는 gRPC 서비스를 구축할 수 없습니다. 더 정확히 말하면, Protobuf 파일에는 서비스 정의, 서비스 메서드, 그리고 교환될 메시지 형식이 모두 포함됩니다. 따라서 gRPC 서비스를 이해하려면 해당 정의 파일을 살펴보는 것이 가장 중요하다고 할 수 있습니다. 다음 레슨에서는 우리가 만들 gRPC 서비스에 사용될 Protobuf 파일을 자세히 보여드릴 것입니다.
|
||||
|
||||
|
||||
# gRPC 실행하기
|
||||
|
||||
|
||||
# 참고 자료
|
||||
|
||||
- https://aws.amazon.com/ko/compare/the-difference-between-grpc-and-rest/
|
||||
* **[docs/MANUSCRIPT.md](docs/MANUSCRIPT.md)**: JSON, HTTP, gRPC 통신의 원리와 배경지식(REST의 한계와 gRPC 도입 이유 등)을 담은 본 프로젝트 공식 개념서
|
||||
* **[examples/grpcentity/README.md](examples/grpcentity/README.md)**: Protobuf 빌드 컴파일 가이드 및 상세 소스코드 구현체 분석 자료
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# gRPC 튜토리얼 원고 (Manuscript)
|
||||
|
||||
본 문서는 `grpccanary` 프로젝트의 개념적 학습 자료를 모아둔 문서입니다. JSON 데이터 포맷의 이해부터 HTTP, 그리고 마이크로서비스 환경에서 gRPC가 왜 필요한지에 대한 상세한 배경을 설명합니다.
|
||||
|
||||
---
|
||||
|
||||
## 1. JSON이란?
|
||||
|
||||
JSON(JavaScript Object Notation)은 데이터를 구조화하여 전송하기 위해 널리 사용되는 가볍고 읽기 쉬운 텍스트 기반의 데이터 포맷입니다. 대부분의 현대 프로그래밍 언어에서 기본적으로 지원하며, 특히 HTTP 기반 REST API의 데이터 교환 규격으로 오랫동안 사랑받아 왔습니다.
|
||||
|
||||
---
|
||||
|
||||
## 2. HTTP란?
|
||||
|
||||
HTTP(Hypertext Transfer Protocol)는 웹 브라우저와 웹 서버 간에 데이터를 주고받기 위한 통신 프로토콜입니다.
|
||||
|
||||
### `gin-gonic`을 이용한 http 서버 구현하기
|
||||
Go 언어에서는 전통적인 `net/http` 표준 라이브러리 외에도, 성능이 뛰어나고 라우팅 기능이 강력한 `gin-gonic/gin` 프레임워크를 널리 활용하여 RESTful 웹 API 서버를 구축합니다.
|
||||
|
||||
---
|
||||
|
||||
## 3. gRPC란?
|
||||
|
||||
Go 언어에서 gRPC를 어떻게 활용하는지 전반적으로 살펴보겠습니다.
|
||||
|
||||
### gRPC가 필요한 이유: 어느 개발팀의 이야기
|
||||
|
||||
어느 날, 성장하는 스타트업의 백엔드 개발자 민우는 골치 아픈 버그를 마주했습니다. 서비스가 마이크로서비스 아키텍처(MSA)로 전환되면서, 회원 서비스(Go)와 주문 서비스(Python)가 서로 HTTP/JSON API로 통신하기 시작했는데, 최근 회원 서비스의 응답 필드 이름이 `user_id`에서 `userId`로 변경되면서 주문 서비스가 마비된 것입니다.
|
||||
|
||||
"사전 공유가 누락되었네요. 죄송합니다..." 회원 담당 팀원의 사과로 버그는 금방 고쳐졌지만, 민우는 근본적인 질문을 던지게 되었습니다.
|
||||
'왜 서비스 간의 통신 규칙(계약)을 코드 레벨에서 강제할 수 없을까?'
|
||||
|
||||
REST와 JSON은 단순하고 사람이 읽기 쉽다는 훌륭한 장점이 있어 인터넷망을 통한 클라이언트-서버 통신에 널리 쓰입니다. 하지만 대규모 마이크로서비스 환경에서 시스템 내부의 서비스 간 통신(Internal RPC)용으로는 다음과 같은 한계를 드러내곤 합니다:
|
||||
1. **느슨한 계약(Loose Contract)**: API 스펙 문서가 최신화되지 않으면 언제든 타입 오류나 필드 누락으로 인한 런타임 에러가 발생할 수 있습니다.
|
||||
2. **비효율적인 직렬화**: 텍스트 기반의 JSON 데이터는 컴퓨터가 처리하기에 너무 무겁고, 네트워크 대역폭도 많이 차지합니다.
|
||||
3. **반복되는 클라이언트 코드 작성**: 파트너 서비스가 고유한 API를 제공할 때마다, 이를 호출하기 위한 HTTP 클라이언트 패키지 코드를 다국어별로 매번 새로 작성해야 합니다.
|
||||
|
||||
이러한 문제들을 해결하기 위해 구글은 **gRPC**를 개발했습니다. gRPC는 다음과 같은 차별점을 통해 민우가 겪었던 어려움을 해결해 줍니다:
|
||||
* **프로토콜 버퍼(Protobuf) 기반의 강력한 스키마 계약**: `.proto` 파일 하나로 서비스 통신 규약을 선언하고, 이를 컴파일하여 여러 프로그래밍 언어의 구체적인 클라이언트/서버 코드를 자동으로 생성합니다. 즉, 컴파일 단계에서 스키마 계약 불일치 오류를 차단합니다.
|
||||
* **바이너리 프로토콜**: 텍스트가 아닌 이진 데이터 형식을 사용하여 통신 속도가 JSON 방식에 비해 훨씬 빠르고 가볍습니다.
|
||||
* **HTTP/2 기반**: 하나의 커넥션을 다중화(Multiplexing)하여 사용하므로 네트워크 리소스 효율성이 매우 높습니다.
|
||||
|
||||
---
|
||||
|
||||
## 4. gRPC 개요
|
||||
|
||||
위와 같이 gRPC가 고안된 배경과 필요성을 바탕으로, 구체적인 특징과 개발 프로세스를 살펴보겠습니다.
|
||||
|
||||
gRPC 서버와 클라이언트를 개발하는 과정은 크게 세 단계로 나뉩니다:
|
||||
1. **인터페이스 정의 언어(IDL) 파일 생성**: 인터페이스를 계약(Contract)으로 정의합니다.
|
||||
2. **gRPC 서버 개발**: 이 정의를 기반으로 서비스를 구현합니다.
|
||||
3. **gRPC 클라이언트 개발**: 해당 서버와 통신하는 코드를 개발합니다.
|
||||
|
||||
### 4.1 장점
|
||||
gRPC의 주요 장점은 다음과 같습니다:
|
||||
* **빠른 데이터 교환**: 바이너리 데이터 형식을 사용하여 일반 텍스트 기반 서비스보다 훨씬 빠르게 데이터를 교환합니다.
|
||||
* **간편한 개발 도구**: 풍부한 명령줄 도구들을 제공하여 개발 작업을 더욱 간단하고 신속하게 만듭니다.
|
||||
* **쉬운 서버/클라이언트 생성**: gRPC 서비스의 함수와 메시지를 정의한 후에는 RESTful 서비스보다 서버와 클라이언트를 더 쉽게 생성할 수 있습니다.
|
||||
* **스트리밍 지원**: 스트리밍 서비스에 효과적으로 활용될 수 있습니다.
|
||||
* **세부 사항 자동 처리**: 데이터 교환의 복잡한 세부 사항을 gRPC가 자동으로 처리해주므로 개발자가 신경 쓸 필요가 없습니다.
|
||||
|
||||
> [!NOTE]
|
||||
> 이 장점 목록만 보고 gRPC가 모든 문제의 완벽한 해결책이라고 오해해서는 안 됩니다. 항상 현재 작업에 가장 적합한 도구나 기술을 선택하는 것이 중요합니다.
|
||||
|
||||
### 4.2 프로토콜 버퍼 (Protobuf)
|
||||
프로토콜 버퍼(Protobuf)는 구조화된 데이터를 효율적으로 직렬화하는 방법입니다. Protobuf는 IDL(인터페이스 정의 언어)의 일부로, 데이터 교환 시 바이너리 형식을 사용하기 때문에 일반 텍스트 기반 직렬화 형식보다 훨씬 적은 공간을 차지합니다. 하지만 데이터를 기계가 사용하고 사람이 읽을 수 있도록 하려면 각각 인코딩과 디코딩 과정이 필요합니다. Protobuf는 각 프로그래밍 언어에서 기본적으로 지원하는 데이터 타입으로 변환되는 자체 데이터 타입을 제공합니다.
|
||||
|
||||
일반적으로 IDL 파일은 모든 gRPC 서비스의 핵심입니다. 이는 데이터 교환 형식과 서비스 인터페이스를 정의하기 때문입니다. Protobuf 파일 없이는 gRPC 서비스를 구축할 수 없습니다. 더 정확히 말하면, Protobuf 파일에는 서비스 정의, 서비스 메서드, 그리고 교환될 메시지 형식이 모두 포함됩니다.
|
||||
|
||||
---
|
||||
|
||||
## 5. 참고 자료
|
||||
|
||||
* [gRPC와 REST의 차이점 (AWS)](https://aws.amazon.com/ko/compare/the-difference-between-grpc-and-rest/)
|
||||
@@ -8,7 +8,7 @@
|
||||
- 서버는 클라이언트에게 주어진 길이의 무작위로 생성된 비밀번호를 반환해야 합니다.
|
||||
- 서버는 클라이언트에게 무작위 정수를 반환해야 합니다.
|
||||
|
||||
gRPC 클라이언트와 서버 개발을 시작하기 전에, IDL 파일을 먼저 정의해야 합니다. IDL 파일과 관련된 파일들을 관리하기 위해 별도의 GitHub 저장소가 필요하며, 여기서는 https://github.com/Educative-Content/protoapi 를 사용합니다.
|
||||
gRPC 클라이언트와 서버 개발을 시작하기 전에, IDL 파일을 먼저 정의해야 합니다. IDL 정의는 이 저장소 루트에 위치한 `protoapi.proto` 파일을 사용합니다.
|
||||
|
||||
## IDL 파일의 구조
|
||||
|
||||
@@ -23,10 +23,10 @@ syntax = "proto3";
|
||||
```proto
|
||||
syntax = "proto3";
|
||||
|
||||
option go_package = "./;protoapi";
|
||||
option go_package = "./protoapi/;protoapi";
|
||||
```
|
||||
|
||||
gRPC 도구들은 이 `.proto` 파일로부터 Go 코드를 생성할 것입니다. 위 라인은 생성될 Go 패키지의 이름이 `protoapi`임을 명시합니다. `./`를 사용했기 때문에 출력 파일은 `protoapi.proto`와 동일한 현재 디렉토리에 생성됩니다.
|
||||
gRPC 도구들은 이 `.proto` 파일로부터 Go 코드를 생성할 것입니다. 위 라인은 생성될 Go 패키지의 이름이 `protoapi`임을 명시합니다. `./protoapi/`를 사용했기 때문에 출력 파일은 `protoapi/` 하위 디렉토리에 생성됩니다.
|
||||
|
||||
```proto
|
||||
service Random {
|
||||
@@ -75,6 +75,8 @@ message RequestDateTime {
|
||||
|
||||
위 두 메시지는 `GetDate` 메서드의 동작을 지원하기 위한 것입니다. `RequestDateTime` 메시지는 실질적인 데이터를 담고 있지 않은 더미 메시지입니다. 단지 클라이언트가 서버로 보내는 메시지가 필요할 뿐이며, `Value` 필드에는 어떤 종류의 정보든 저장할 수 있습니다. 서버가 반환하는 정보는 `DateTime` 메시지에 `string` 값으로 저장됩니다.
|
||||
|
||||
> **참고**: `RequestDateTime`의 `Value` 필드 번호가 `2`로 지정되어 있습니다. 프로토콜 버퍼에서 필드 번호는 태그 번호로 사용되며 고유한 번호라면 임의의 값을 가질 수 있지만, 일반적으로는 첫 필드에 `1`을 사용하는 것이 관례입니다.
|
||||
|
||||
```proto
|
||||
// For random password
|
||||
message RequestPass {
|
||||
@@ -100,7 +102,7 @@ message RandomPass {
|
||||
|
||||
다음 중요한 단계는 이 파일을 Go에서 사용할 수 있는 형식으로 변환하는 것입니다. `protoapi.proto`나 다른 `.proto` 파일을 처리하여 관련된 Go `.pb.go` 파일을 생성하기 위해 몇 가지 추가 도구를 다운로드해야 합니다. 프로토콜 버퍼 컴파일러 바이너리의 이름은 `protoc`입니다. macOS에서는 `brew install protobuf` 명령을 사용하여 `protoc`를 설치해야 합니다. 마찬가지로, Homebrew를 사용하여 `protoc-gen-go-grpc`와 `protoc-gen-go` 패키지도 설치해야 합니다. 이 두 패키지는 Go와 관련이 있습니다.
|
||||
|
||||
Linux에서는 선호하는 패키지 관리자를 사용하여 `protobuf`를 설치하고, `go install github.com/golang/protobuf/protoc-gen-go@latest` 명령을 사용하여 `protoc-gen-go`를 설치해야 합니다. 마찬가지로, `go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest`를 실행하여 `protoc-gen-go-grpc` 실행 파일을 설치해야 합니다.
|
||||
Linux에서는 선호하는 패키지 관리자를 사용하여 `protobuf`를 설치하고, `go install google.golang.org/protobuf/cmd/protoc-gen-go@latest` 명령을 사용하여 `protoc-gen-go`를 설치해야 합니다. 마찬가지로, `go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest`를 실행하여 `protoc-gen-go-grpc` 실행 파일을 설치해야 합니다.
|
||||
|
||||
> 참고: Go 1.16부터는 모듈 모드에서 패키지를 빌드하고 설치하는 데 `go install`을 사용하는 것이 권장됩니다. `go get`의 사용은 더 이상 사용되지 않습니다. `go install`을 사용할 때는 최신 버전을 설치하기 위해 패키지 이름 뒤에 `@latest`를 추가하는 것을 잊지 마세요.
|
||||
|
||||
@@ -115,7 +117,7 @@ protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \
|
||||
--go-grpc_opt=paths=source_relative protoapi.proto
|
||||
```
|
||||
|
||||
이 명령을 실행하면, GitHub 저장소의 루트 디렉토리에 `protoapi_grpc.pb.go`와 `protoapi.pb.go`라는 두 개의 파일이 생성됩니다. `protoapi.pb.go` 소스 코드 파일에는 메시지가 포함되어 있고, `protoapi_grpc.pb.go`에는 서비스가 포함되어 있습니다.
|
||||
이 명령을 실행하면, 리포지토리 루트 하위의 `protoapi` 디렉토리에 `protoapi_grpc.pb.go`와 `protoapi.pb.go`라는 두 개의 파일이 생성됩니다. `protoapi.pb.go` 소스 코드 파일에는 메시지가 포함되어 있고, `protoapi_grpc.pb.go`에는 서비스가 포함되어 있습니다.
|
||||
|
||||
`protoapi_grpc.pb.go`의 첫 열 줄은 다음과 같습니다:
|
||||
|
||||
@@ -144,8 +146,8 @@ codes "google.golang.org/grpc/codes"
|
||||
```go
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.17.3
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v3.21.12
|
||||
// source: protoapi.proto
|
||||
|
||||
package protoapi
|
||||
@@ -153,4 +155,68 @@ package protoapi
|
||||
|
||||
`protoapi_grpc.pb.go`와 `protoapi.pb.go`는 모두 `protoapi` Go 패키지의 일부이므로, 코드에서 한 번만 포함하면 됩니다.
|
||||
|
||||
```
|
||||
## gRPC 서버 개발
|
||||
|
||||
IDL을 통해 생성된 Go 코드를 기반으로, 실제 비즈니스 로직을 수행할 gRPC 서버([server.go](./server.go))를 구현합니다.
|
||||
|
||||
### 1. 서비스 인터페이스 구현
|
||||
우리가 `.proto` 파일에 정의한 `Random` 서비스의 메서드들은 `RandomServer` 구조체 타입을 통해 구현됩니다. 이 구조체는 stub 코드의 `UnimplementedRandomServer`를 임베딩하여 기본 호환성을 확보합니다.
|
||||
|
||||
```go
|
||||
type RandomServer struct {
|
||||
protoapi.UnimplementedRandomServer
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 서비스 메서드 작성
|
||||
서버는 IDL에 기술된 세 가지 RPC 메서드인 `GetDate`, `GetRandom`, `GetRandomPass`를 각각 실제 동작 코드로 구현합니다.
|
||||
|
||||
* **`GetDate`**: 현재 날짜와 시간 정보를 반환합니다.
|
||||
* **`GetRandom`**: 전달받은 시드(`Seed`)와 위치(`Place`) 매개변수를 이용해 의사 난수를 생성하고 반환합니다.
|
||||
* **`GetRandomPass`**: 지정된 길이(`Length`)의 무작위 문자열 비밀번호를 빌드하여 반환합니다.
|
||||
|
||||
### 3. gRPC 서버 시작 (`ServerRun`)
|
||||
네트워크 포트 청취를 개시하고, gRPC 서버 객체를 인스턴스화한 후 서비스를 등록하여 대기 상태에 들어갑니다.
|
||||
|
||||
```go
|
||||
func ServerRun(addr string) {
|
||||
server := grpc.NewServer()
|
||||
var randomServer RandomServer
|
||||
protoapi.RegisterRandomServer(server, randomServer)
|
||||
|
||||
// 외부 CLI 도구(예: grpcurl)의 디버깅을 위해 리플렉션 등록
|
||||
reflection.Register(server)
|
||||
|
||||
listen, err := net.Listen("tcp", port)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Serving requests...")
|
||||
server.Serve(listen)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## gRPC 클라이언트 개발
|
||||
|
||||
서버로 RPC 요청을 전송하고 결과를 출력하는 gRPC 클라이언트([client.go](./client.go))의 흐름은 다음과 같습니다.
|
||||
|
||||
### 1. 서버 접속 채널 구축
|
||||
클라이언트는 보안 자격 증명 옵션을 지정하여 서버 네트워크 주소로 커넥션을 생성합니다. (본 예제에서는 로컬 테스트용으로 `insecure` 자격 증명을 이용해 평문 채널을 구축합니다.)
|
||||
|
||||
```go
|
||||
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
```
|
||||
|
||||
### 2. 클라이언트 인스턴스 및 호출 함수 정의
|
||||
채널 연결 완료 후 `protoapi.NewRandomClient(conn)`를 통해 클라이언트 객체를 생성하고, 개별 RPC 메서드들을 호출하는 래퍼 함수들을 정의해 서버에 값을 질의합니다.
|
||||
|
||||
* **`AskingDateTime`** -> `client.GetDate()` 호출
|
||||
* **`AskPass`** -> `client.GetRandomPass()` 호출
|
||||
* **`AskRandom`** -> `client.GetRandom()` 호출
|
||||
|
||||
### 3. 실행 엔트리포인트 (`ClientRun`)
|
||||
각 RPC 메서드를 호출하여 서버로부터 전달받은 시간 값, 난수 비밀번호, 무작위 난수들을 터미널 표준 출력(`fmt.Println`)으로 출력해 줍니다.
|
||||
Reference in New Issue
Block a user