refactor: rename examples/ directory to lib/ and update all path references
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
grpccanary/
|
grpccanary/
|
||||||
├── README.md # 본 프로젝트 종합 소개 및 실행 가이드 (교육용)
|
├── README.md # 본 프로젝트 종합 소개 및 실행 가이드 (교육용)
|
||||||
├── go.mod / go.sum # Go 모듈 의존성 정의 (Go 1.25.4+)
|
├── go.mod / go.sum # Go 모듈 의존성 정의 (Go 1.25.4+)
|
||||||
├── examples/
|
├── lib/
|
||||||
│ ├── main.go # 학습 예제 통합 실행 진입점 (수동 전환)
|
│ ├── main.go # 학습 예제 통합 실행 진입점 (수동 전환)
|
||||||
│ ├── jsonexample/ # 1단계: JSON 데이터 다루기 실습 예제
|
│ ├── jsonexample/ # 1단계: JSON 데이터 다루기 실습 예제
|
||||||
│ ├── httpentity/ # 2단계: HTTP & Gin 웹 서버 실습 예제 (WIP)
|
│ ├── httpentity/ # 2단계: HTTP & Gin 웹 서버 실습 예제 (WIP)
|
||||||
@@ -39,13 +39,13 @@ grpccanary/
|
|||||||
└── GRPC.md # 3단계: gRPC 통신 구현 상세 가이드
|
└── GRPC.md # 3단계: gRPC 통신 구현 상세 가이드
|
||||||
```
|
```
|
||||||
|
|
||||||
### 1단계: JSON 데이터 다루기 (`examples/jsonexample`)
|
### 1단계: JSON 데이터 다루기 (`lib/jsonexample`)
|
||||||
* Go 표준 라이브러리인 `encoding/json`을 활용하여 구조체(Struct)와 JSON 데이터 간의 마샬링(Serialization) 및 언마샬링(Deserialization) 기법을 학습합니다.
|
* Go 표준 라이브러리인 `encoding/json`을 활용하여 구조체(Struct)와 JSON 데이터 간의 마샬링(Serialization) 및 언마샬링(Deserialization) 기법을 학습합니다.
|
||||||
|
|
||||||
### 2단계: HTTP & Gin 웹 서버 (`examples/httpentity`)
|
### 2단계: HTTP & Gin 웹 서버 (`lib/httpentity`)
|
||||||
* 대중적인 Go 웹 프레임워크 `gin-gonic`을 활용해 RESTful API 사양을 구축하는 방법을 이해합니다. (현재 주석 해제 후 실습하도록 설계된 Work-in-Progress 단계)
|
* 대중적인 Go 웹 프레임워크 `gin-gonic`을 활용해 RESTful API 사양을 구축하는 방법을 이해합니다. (현재 주석 해제 후 실습하도록 설계된 Work-in-Progress 단계)
|
||||||
|
|
||||||
### 3단계: gRPC 통신 구현 (`examples/grpcentity`)
|
### 3단계: gRPC 통신 구현 (`lib/grpcentity`)
|
||||||
* `.proto` 정의를 바탕으로 통신 스키마 계약을 강제하고, Go 언어로 gRPC 서버를 띄워 클라이언트가 날짜/시간, 무작위 비밀번호 및 정수 데이터를 실시간 원격 호출로 송수신하는 분산 통신 기초를 학습합니다.
|
* `.proto` 정의를 바탕으로 통신 스키마 계약을 강제하고, Go 언어로 gRPC 서버를 띄워 클라이언트가 날짜/시간, 무작위 비밀번호 및 정수 데이터를 실시간 원격 호출로 송수신하는 분산 통신 기초를 학습합니다.
|
||||||
* `.proto` 정의를 바탕으로 통신 스키마 계약을 강제하고, Go 언어로 gRPC 서버를 띄워 클라이언트가 날짜/시간, 무작위 비밀번호 및 정수 데이터를 실시간 원격 호출로 송수신하는 분산 통신 기초를 학습합니다.
|
* `.proto` 정의를 바탕으로 통신 스키마 계약을 강제하고, Go 언어로 gRPC 서버를 띄워 클라이언트가 날짜/시간, 무작위 비밀번호 및 정수 데이터를 실시간 원격 호출로 송수신하는 분산 통신 기초를 학습합니다.
|
||||||
|
|
||||||
@@ -73,13 +73,13 @@ grpccanary/
|
|||||||
### 2. 실습 예제 실행 방법 (진입점 전환)
|
### 2. 실습 예제 실행 방법 (진입점 전환)
|
||||||
이 프로젝트는 교육적 목적을 위해 **하나의 `main.go` 파일 안에서 주석 처리를 통해 학습 단계를 수동 전환**하여 실행하도록 설계되어 있습니다.
|
이 프로젝트는 교육적 목적을 위해 **하나의 `main.go` 파일 안에서 주석 처리를 통해 학습 단계를 수동 전환**하여 실행하도록 설계되어 있습니다.
|
||||||
|
|
||||||
1. **[examples/main.go](examples/main.go)** 파일을 엽니다.
|
1. **[lib/main.go](lib/main.go)** 파일을 엽니다.
|
||||||
2. 아래와 같이 실행하고자 하는 예제의 주석을 해제하고 다른 예제는 주석 처리합니다.
|
2. 아래와 같이 실행하고자 하는 예제의 주석을 해제하고 다른 예제는 주석 처리합니다.
|
||||||
* *JSON 예제 실행 시*: `jsonexample.JsonParsingExample()` 활성화
|
* *JSON 예제 실행 시*: `jsonexample.JsonParsingExample()` 활성화
|
||||||
* *gRPC 예제 실행 시*: `grpcSample()` 활성화 (미사용 import 에러를 피하기 위해 `jsonexample` import는 주석 처리 필요)
|
* *gRPC 예제 실행 시*: `grpcSample()` 활성화 (미사용 import 에러를 피하기 위해 `jsonexample` import는 주석 처리 필요)
|
||||||
3. 루트 디렉토리에서 다음 명령어로 실행합니다:
|
3. 루트 디렉토리에서 다음 명령어로 실행합니다:
|
||||||
```bash
|
```bash
|
||||||
go run ./examples
|
go run ./lib
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. gRPC 예제 동작 흐름 및 기대 출력
|
### 3. gRPC 예제 동작 흐름 및 기대 출력
|
||||||
@@ -106,4 +106,4 @@ Sensing Update Message: Sensing data updated successfully for device sensor-room
|
|||||||
* **[docs/JSON.md](docs/JSON.md)**: 1단계 JSON 데이터 다루기 상세 학습 가이드
|
* **[docs/JSON.md](docs/JSON.md)**: 1단계 JSON 데이터 다루기 상세 학습 가이드
|
||||||
* **[docs/HTTP.md](docs/HTTP.md)**: 2단계 HTTP & Gin 웹 프레임워크 상세 학습 가이드
|
* **[docs/HTTP.md](docs/HTTP.md)**: 2단계 HTTP & Gin 웹 프레임워크 상세 학습 가이드
|
||||||
* **[docs/GRPC.md](docs/GRPC.md)**: 3단계 gRPC & Protobuf 상세 학습 가이드 (컴파일 절차 및 소스코드 구현체 분석 포함)
|
* **[docs/GRPC.md](docs/GRPC.md)**: 3단계 gRPC & Protobuf 상세 학습 가이드 (컴파일 절차 및 소스코드 구현체 분석 포함)
|
||||||
* **[examples/grpcentity/README.md](examples/grpcentity/README.md)**: gRPC 실습 디렉토리 안내 및 `docs/GRPC.md` 심화 가이드로의 링크
|
* **[lib/grpcentity/README.md](lib/grpcentity/README.md)**: gRPC 실습 디렉토리 안내 및 `docs/GRPC.md` 심화 가이드로의 링크
|
||||||
|
|||||||
+9
-9
@@ -82,7 +82,7 @@ gRPC는 HTTP/2를 기반으로 구축된 구글의 고성능 오픈소스 원격
|
|||||||
|
|
||||||
### 3.4 명세서 소스코드 및 구체적 분석
|
### 3.4 명세서 소스코드 및 구체적 분석
|
||||||
|
|
||||||
실습 디렉토리 내에 선언된 [protoapi.proto](../examples/grpcentity/protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다.
|
실습 디렉토리 내에 선언된 [protoapi.proto](../lib/grpcentity/protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다.
|
||||||
|
|
||||||
```proto
|
```proto
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
@@ -175,7 +175,7 @@ gRPC 빌드 및 코드 생성 환경을 구축하기 위해 사용되는 세 가
|
|||||||
작성된 스키마 명세를 빌드하여 Go 소스코드를 생성하기 위해 다음 명령어를 구동합니다:
|
작성된 스키마 명세를 빌드하여 Go 소스코드를 생성하기 위해 다음 명령어를 구동합니다:
|
||||||
```bash
|
```bash
|
||||||
# 해당 실습 디렉터리로 이동 후 컴파일 실행
|
# 해당 실습 디렉터리로 이동 후 컴파일 실행
|
||||||
cd examples/grpcentity
|
cd lib/grpcentity
|
||||||
protoc --go_out=. --go-grpc_out=. protoapi.proto
|
protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
|||||||
|
|
||||||
**Go 패키지 지정 옵션과의 결합 규칙**:
|
**Go 패키지 지정 옵션과의 결합 규칙**:
|
||||||
해당 출력 경로 옵션들은 단독으로 파일의 최종 위치를 고정하지 않습니다. 컴파일러는 지정된 기준 경로(예: `.`)에 `.proto` 스펙 내부의 `option go_package = "./protoapi;protoapi"` 설정값을 조합하여 최종 디렉터리 경로를 생성합니다.
|
해당 출력 경로 옵션들은 단독으로 파일의 최종 위치를 고정하지 않습니다. 컴파일러는 지정된 기준 경로(예: `.`)에 `.proto` 스펙 내부의 `option go_package = "./protoapi;protoapi"` 설정값을 조합하여 최종 디렉터리 경로를 생성합니다.
|
||||||
이에 따라 **컴파일 대상 디렉터리(`.`)**와 **상세 패키지 주소(`./protoapi`)**가 결합되어 `examples/grpcentity/protoapi/` 경로가 자동 생성되며, 그 하위에 다음 소스코드들이 정상 배치됩니다:
|
이에 따라 **컴파일 대상 디렉터리(`.`)**와 **상세 패키지 주소(`./protoapi`)**가 결합되어 `lib/grpcentity/protoapi/` 경로가 자동 생성되며, 그 하위에 다음 소스코드들이 정상 배치됩니다:
|
||||||
* `protoapi.pb.go`: 명세에 정의된 메시지(Message) 규격을 Go 구조체로 변환한 파일입니다.
|
* `protoapi.pb.go`: 명세에 정의된 메시지(Message) 규격을 Go 구조체로 변환한 파일입니다.
|
||||||
* `protoapi_grpc.pb.go`: 클라이언트와 서버 통신을 위한 원격 호출(Service) 규격을 구현한 파일입니다.
|
* `protoapi_grpc.pb.go`: 클라이언트와 서버 통신을 위한 원격 호출(Service) 규격을 구현한 파일입니다.
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
|||||||
|
|
||||||
컴파일러를 통해 통신을 위한 스터브(Stub) 코드가 확보되었으므로, 이를 기반으로 서버와 클라이언트의 비즈니스 로직을 연결하는 상세 코드를 검토합니다.
|
컴파일러를 통해 통신을 위한 스터브(Stub) 코드가 확보되었으므로, 이를 기반으로 서버와 클라이언트의 비즈니스 로직을 연결하는 상세 코드를 검토합니다.
|
||||||
|
|
||||||
### 5.1 gRPC 서버 구현 분석 ([server.go](../examples/grpcentity/server.go))
|
### 5.1 gRPC 서버 구현 분석 ([server.go](../lib/grpcentity/server.go))
|
||||||
|
|
||||||
* **서버 서비스 인터페이스 매핑 구조체 (`IoTServer`)**:
|
* **서버 서비스 인터페이스 매핑 구조체 (`IoTServer`)**:
|
||||||
```go
|
```go
|
||||||
@@ -240,7 +240,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
|||||||
* **쉬운 설명**: `:8080` 포트로 통하는 소켓(전화선)을 개통하고, 기기들의 전화(접속 및 호출)가 오기를 기다리며 대기 상태로 들어가는 서버 구동 시작점입니다.
|
* **쉬운 설명**: `:8080` 포트로 통하는 소켓(전화선)을 개통하고, 기기들의 전화(접속 및 호출)가 오기를 기다리며 대기 상태로 들어가는 서버 구동 시작점입니다.
|
||||||
* **상세 설명**: 지정된 포트(기본 포트 `:8080`)의 TCP 소켓 포트를 활성화하고, 클라이언트의 접속 및 RPC 서비스 호출에 대해 지속적으로 대기하는 리스너 구동의 진입점입니다.
|
* **상세 설명**: 지정된 포트(기본 포트 `:8080`)의 TCP 소켓 포트를 활성화하고, 클라이언트의 접속 및 RPC 서비스 호출에 대해 지속적으로 대기하는 리스너 구동의 진입점입니다.
|
||||||
|
|
||||||
### 5.2 gRPC 클라이언트 구현 분석 ([client.go](../examples/grpcentity/client.go))
|
### 5.2 gRPC 클라이언트 구현 분석 ([client.go](../lib/grpcentity/client.go))
|
||||||
|
|
||||||
* **원격 서비스 클라이언트 기동 (`NewIoTServiceClient`)**:
|
* **원격 서비스 클라이언트 기동 (`NewIoTServiceClient`)**:
|
||||||
```go
|
```go
|
||||||
@@ -276,7 +276,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
|||||||
### 6.1 `bind: address already in use` (네트워크 소켓 포트 충돌)
|
### 6.1 `bind: address already in use` (네트워크 소켓 포트 충돌)
|
||||||
* **발생 원인**: gRPC 서버 기동 시 설정한 통신 포트 `:8080`이 이미 다른 네트워크 프로세스나 이전 실습 서버의 비정상 종료 등으로 인해 점유되어 바인딩에 실패한 상태입니다.
|
* **발생 원인**: gRPC 서버 기동 시 설정한 통신 포트 `:8080`이 이미 다른 네트워크 프로세스나 이전 실습 서버의 비정상 종료 등으로 인해 점유되어 바인딩에 실패한 상태입니다.
|
||||||
* **조치 방법**:
|
* **조치 방법**:
|
||||||
- `examples/main.go`의 `port` 변수 및 [server.go](../examples/grpcentity/server.go)의 `port` 전역 변수값을 동시에 다른 유휴 포트(예: `:9090`)로 변경하여 구동을 시도합니다.
|
- `lib/main.go`의 `port` 변수 및 [server.go](../lib/grpcentity/server.go)의 `port` 전역 변수값을 동시에 다른 유휴 포트(예: `:9090`)로 변경하여 구동을 시도합니다.
|
||||||
- **🚨 소스코드 설계 제약**: `server.go`에 기재된 `ServerRun(addr string)` 함수는 메인 환경으로부터 주입받은 `addr` 인자값을 사용하지 않고, 패키지 내부 전역 변수인 `port` (하드코딩된 값 `:8080`)를 소켓 리슨 파라미터로 직접 참조하도록 되어 있습니다. 따라서 바인딩 충돌 회피를 위해서는 `main.go`뿐만 아니라 반드시 `server.go` 파일 내부의 전역 변수인 `port` 역시 함께 갱신해 주어야 실제 바인딩 포트 변경이 유효하게 처리됩니다.
|
- **🚨 소스코드 설계 제약**: `server.go`에 기재된 `ServerRun(addr string)` 함수는 메인 환경으로부터 주입받은 `addr` 인자값을 사용하지 않고, 패키지 내부 전역 변수인 `port` (하드코딩된 값 `:8080`)를 소켓 리슨 파라미터로 직접 참조하도록 되어 있습니다. 따라서 바인딩 충돌 회피를 위해서는 `main.go`뿐만 아니라 반드시 `server.go` 파일 내부의 전역 변수인 `port` 역시 함께 갱신해 주어야 실제 바인딩 포트 변경이 유효하게 처리됩니다.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -324,7 +324,7 @@ message DownloadRequest {
|
|||||||
```
|
```
|
||||||
* **설계 포인트**: `stream` 키워드가 들어간 위치에 주목합니다. `UploadFile`은 입력에 `stream`이 붙어 클라이언트 스트리밍을, `DownloadFile`은 반환(returns)에 `stream`이 붙어 서버 스트리밍 채널을 개설합니다.
|
* **설계 포인트**: `stream` 키워드가 들어간 위치에 주목합니다. `UploadFile`은 입력에 `stream`이 붙어 클라이언트 스트리밍을, `DownloadFile`은 반환(returns)에 `stream`이 붙어 서버 스트리밍 채널을 개설합니다.
|
||||||
|
|
||||||
### 7.2 서버 저장 및 송수신 구현 ([server.go](../examples/grpcentity/server.go))
|
### 7.2 서버 저장 및 송수신 구현 ([server.go](../lib/grpcentity/server.go))
|
||||||
인메모리 파일 저장소(`fileStore`)를 구현하고 목록 조회(`ListFiles`) 및 서버 다운로드 스트리밍(`DownloadFile`) 핸들러를 정의합니다:
|
인메모리 파일 저장소(`fileStore`)를 구현하고 목록 조회(`ListFiles`) 및 서버 다운로드 스트리밍(`DownloadFile`) 핸들러를 정의합니다:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -392,7 +392,7 @@ func (IoTServer) DownloadFile(r *protoapi.DownloadRequest, stream protoapi.IoTSe
|
|||||||
* **목록 조회**: 동시 접근 보호(Race condition 방지)를 위해 읽기 전용 락(`RLock`)을 획득한 후 인메모리 맵을 순회하며 메타데이터 구조체 목록을 집계해 반환합니다.
|
* **목록 조회**: 동시 접근 보호(Race condition 방지)를 위해 읽기 전용 락(`RLock`)을 획득한 후 인메모리 맵을 순회하며 메타데이터 구조체 목록을 집계해 반환합니다.
|
||||||
* **파일 다운로드**: 대상 파일 쿼리 실패 시 gRPC 표준 에러(`codes.NotFound`)를 반환합니다. 검증 통과 시 루프 내에서 가상 윈도우 슬라이싱을 집행해 청크 구조체를 구성하고, `stream.Send()`로 직렬화 패킷을 클라이언트 버퍼 큐에 기입합니다.
|
* **파일 다운로드**: 대상 파일 쿼리 실패 시 gRPC 표준 에러(`codes.NotFound`)를 반환합니다. 검증 통과 시 루프 내에서 가상 윈도우 슬라이싱을 집행해 청크 구조체를 구성하고, `stream.Send()`로 직렬화 패킷을 클라이언트 버퍼 큐에 기입합니다.
|
||||||
|
|
||||||
### 7.3 클라이언트 송수신 기동 ([client.go](../examples/grpcentity/client.go))
|
### 7.3 클라이언트 송수신 기동 ([client.go](../lib/grpcentity/client.go))
|
||||||
클라이언트는 업로드에 성공한 뒤, 서버에 파일 목록 조회를 요구하고, 다운로드 스트림을 개설해 조각 데이터를 재조립하여 무결성을 검사합니다.
|
클라이언트는 업로드에 성공한 뒤, 서버에 파일 목록 조회를 요구하고, 다운로드 스트림을 개설해 조각 데이터를 재조립하여 무결성을 검사합니다.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -435,7 +435,7 @@ func AskDownloadFile(ctx context.Context, m protoapi.IoTServiceClient, fileName
|
|||||||
|
|
||||||
본 기초 실습을 끝마치셨다면, 아래 과제를 해결해보세요:
|
본 기초 실습을 끝마치셨다면, 아래 과제를 해결해보세요:
|
||||||
|
|
||||||
1. **약속 스펙 확장해 보기**: [protoapi.proto](../examples/grpcentity/protoapi.proto) 파일에 새로운 환경 데이터(예: 미세먼지 수치 `double Dust = 4;`)를 슬쩍 얹어본 뒤, 직접 번역기를 새로 돌리고 Go 소스코드를 고치며 확장해 봅니다.
|
1. **약속 스펙 확장해 보기**: [protoapi.proto](../lib/grpcentity/protoapi.proto) 파일에 새로운 환경 데이터(예: 미세먼지 수치 `double Dust = 4;`)를 슬쩍 얹어본 뒤, 직접 번역기를 새로 돌리고 Go 소스코드를 고치며 확장해 봅니다.
|
||||||
2. **proto 명세서 물리 분할하기 (실전 모듈화)**: 현재 단일 파일로 구성된 `protoapi.proto`를 기능 성격에 맞춰 `iot_service.proto`(Unary 제어 메시지)와 `file_transfer.proto`(스트리밍 전송 메시지) 2개의 파일로 쪼개어 구성해 봅니다. 이때 두 파일의 `option go_package` 공유 방식과 번역기(`protoc`) 명령어를 다중 타겟(또는 `*.proto`)으로 조율하여 정상 빌드해 보세요.
|
2. **proto 명세서 물리 분할하기 (실전 모듈화)**: 현재 단일 파일로 구성된 `protoapi.proto`를 기능 성격에 맞춰 `iot_service.proto`(Unary 제어 메시지)와 `file_transfer.proto`(스트리밍 전송 메시지) 2개의 파일로 쪼개어 구성해 봅니다. 이때 두 파일의 `option go_package` 공유 방식과 번역기(`protoc`) 명령어를 다중 타겟(또는 `*.proto`)으로 조율하여 정상 빌드해 보세요.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
+2
-2
@@ -27,9 +27,9 @@ Go 진영에서 대표적으로 사랑받는 웹 프레임워크 중 하나로,
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. 실습 코드 분석 (`examples/httpentity/server.go`)
|
## 3. 실습 코드 분석 (`lib/httpentity/server.go`)
|
||||||
|
|
||||||
저장소의 [server.go](../examples/httpentity/server.go) 파일에는 Gin 라우터를 구성하고 API 서버와 정적 웹 서빙을 혼합하여 라우팅을 우회 처리하는 설계 패턴이 주석 상태로 존재합니다.
|
저장소의 [server.go](../lib/httpentity/server.go) 파일에는 Gin 라우터를 구성하고 API 서버와 정적 웹 서빙을 혼합하여 라우팅을 우회 처리하는 설계 패턴이 주석 상태로 존재합니다.
|
||||||
|
|
||||||
### 3.1 라우터 엔진 분리 및 통합 핸들링
|
### 3.1 라우터 엔진 분리 및 통합 핸들링
|
||||||
```go
|
```go
|
||||||
|
|||||||
+2
-2
@@ -21,9 +21,9 @@ Go 구조체로 JSON 데이터를 다룰 때 핵심적인 과정입니다.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. 실습 코드 분석 (`examples/jsonexample/json_parser.go`)
|
## 2. 실습 코드 분석 (`lib/jsonexample/json_parser.go`)
|
||||||
|
|
||||||
저장소의 [json_parser.go](../examples/jsonexample/json_parser.go) 파일은 (1) `map[string]interface{}`와의 직렬화 및 (2) 구조체(`Person`)를 이용한 매핑 방식을 모두 다룹니다.
|
저장소의 [json_parser.go](../lib/jsonexample/json_parser.go) 파일은 (1) `map[string]interface{}`와의 직렬화 및 (2) 구조체(`Person`)를 이용한 매핑 방식을 모두 다룹니다.
|
||||||
|
|
||||||
### 2.1 구조체 태그(Struct Tag) 정의
|
### 2.1 구조체 태그(Struct Tag) 정의
|
||||||
```go
|
```go
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# examples/grpcentity 실습 설명서
|
# lib/grpcentity 실습 설명서
|
||||||
|
|
||||||
본 디렉토리는 Go 언어를 활용한 gRPC 서버 및 클라이언트 실습 예제를 포함하고 있습니다.
|
본 디렉토리는 Go 언어를 활용한 gRPC 서버 및 클라이언트 실습 예제를 포함하고 있습니다.
|
||||||
|
|
||||||
@@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
## 🚀 빠른 실행 방법
|
## 🚀 빠른 실행 방법
|
||||||
|
|
||||||
이 예제는 리포지토리 루트의 `examples/main.go`를 통해 실행됩니다.
|
이 예제는 리포지토리 루트의 `lib/main.go`를 통해 실행됩니다.
|
||||||
|
|
||||||
1. 리포지토리 루트의 `examples/main.go`를 엽니다.
|
1. 리포지토리 루트의 `lib/main.go`를 엽니다.
|
||||||
2. `main()` 함수 내에서 `grpcSample()`의 주석을 해제합니다.
|
2. `main()` 함수 내에서 `grpcSample()`의 주석을 해제합니다.
|
||||||
3. 리포지토리 루트에서 다음 명령어를 실행합니다:
|
3. 리포지토리 루트에서 다음 명령어를 실행합니다:
|
||||||
```bash
|
```bash
|
||||||
go run ./examples
|
go run ./lib
|
||||||
```
|
```
|
||||||
@@ -3,7 +3,7 @@ package entity
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"grpccanary/examples/grpcentity/protoapi"
|
"grpccanary/lib/grpcentity/protoapi"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
@@ -3,7 +3,7 @@ package entity
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"grpccanary/examples/grpcentity/protoapi"
|
"grpccanary/lib/grpcentity/protoapi"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# examples/httpentity 실습 설명서
|
# lib/httpentity 실습 설명서
|
||||||
|
|
||||||
본 디렉토리는 Go 언어 웹 프레임워크인 Gin(`gin-gonic`)을 활용한 HTTP 웹 API 서버 실습 예제를 포함하고 있습니다.
|
본 디렉토리는 Go 언어 웹 프레임워크인 Gin(`gin-gonic`)을 활용한 HTTP 웹 API 서버 실습 예제를 포함하고 있습니다.
|
||||||
|
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
|
|
||||||
## 🚀 빠른 실행 방법
|
## 🚀 빠른 실행 방법
|
||||||
|
|
||||||
이 예제는 리포지토리 루트의 `examples/main.go`를 통해 실행됩니다.
|
이 예제는 리포지토리 루트의 `lib/main.go`를 통해 실행됩니다.
|
||||||
|
|
||||||
1. 리포지토리 루트의 `examples/main.go`를 엽니다.
|
1. 리포지토리 루트 of `lib/main.go`를 엽니다.
|
||||||
2. `main()` 함수 내에서 `httpentity` API 호출 주석을 해제합니다. (현재 주석 상태로, 추후 구현 완성을 위한 예제 뼈대 파일입니다.)
|
2. `main()` 함수 내에서 `httpentity` API 호출 주석을 해제합니다. (현재 주석 상태로, 추후 구현 완성을 위한 예제 뼈대 파일입니다.)
|
||||||
3. 리포지토리 루트에서 다음 명령어를 실행합니다:
|
3. 리포지토리 루트에서 다음 명령어를 실행합니다:
|
||||||
```bash
|
```bash
|
||||||
go run ./examples
|
go run ./lib
|
||||||
```
|
```
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# examples/jsonexample 실습 설명서
|
# lib/jsonexample 실습 설명서
|
||||||
|
|
||||||
본 디렉토리는 Go 언어 표준 라이브러리(`encoding/json`)를 활용한 JSON 데이터 직렬화 및 역직렬화 실습 예제를 포함하고 있습니다.
|
본 디렉토리는 Go 언어 표준 라이브러리(`encoding/json`)를 활용한 JSON 데이터 직렬화 및 역직렬화 실습 예제를 포함하고 있습니다.
|
||||||
|
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
|
|
||||||
## 🚀 빠른 실행 방법
|
## 🚀 빠른 실행 방법
|
||||||
|
|
||||||
이 예제는 리포지토리 루트의 `examples/main.go`를 통해 실행됩니다.
|
이 예제는 리포지토리 루트의 `lib/main.go`를 통해 실행됩니다.
|
||||||
|
|
||||||
1. 리포지토리 루트의 `examples/main.go`를 엽니다.
|
1. 리포지토리 루트의 `lib/main.go`를 엽니다.
|
||||||
2. `main()` 함수 내에서 `jsonexample.JsonParsingExample()`의 주석을 해제합니다.
|
2. `main()` 함수 내에서 `jsonexample.JsonParsingExample()`의 주석을 해제합니다.
|
||||||
3. 리포지토리 루트에서 다음 명령어를 실행합니다:
|
3. 리포지토리 루트에서 다음 명령어를 실행합니다:
|
||||||
```bash
|
```bash
|
||||||
go run ./examples
|
go run ./lib
|
||||||
```
|
```
|
||||||
@@ -2,8 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
entity "grpccanary/examples/grpcentity"
|
entity "grpccanary/lib/grpcentity"
|
||||||
"grpccanary/examples/jsonexample"
|
"grpccanary/lib/jsonexample"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
+13
-13
@@ -22,7 +22,7 @@ grpccanary/
|
|||||||
│ ├── protoapi.pb.go # 메시지 타입 (protoc-gen-go)
|
│ ├── protoapi.pb.go # 메시지 타입 (protoc-gen-go)
|
||||||
│ └── protoapi_grpc.pb.go # 서비스/클라이언트 stub (protoc-gen-go-grpc)
|
│ └── protoapi_grpc.pb.go # 서비스/클라이언트 stub (protoc-gen-go-grpc)
|
||||||
├── obj.json # JSON 예제용 샘플 데이터 파일
|
├── obj.json # JSON 예제용 샘플 데이터 파일
|
||||||
├── examples/
|
├── lib/
|
||||||
│ ├── main.go # 실행 진입점 (현재는 JSON 예제만 호출하도록 설정됨)
|
│ ├── main.go # 실행 진입점 (현재는 JSON 예제만 호출하도록 설정됨)
|
||||||
│ ├── jsonexample/
|
│ ├── jsonexample/
|
||||||
│ │ └── json_parser.go # encoding/json 마샬링·언마샬링 예제
|
│ │ └── json_parser.go # encoding/json 마샬링·언마샬링 예제
|
||||||
@@ -50,16 +50,16 @@ grpccanary/
|
|||||||
|
|
||||||
## 3. 핵심 구성 요소 (학습용 Go 코드)
|
## 3. 핵심 구성 요소 (학습용 Go 코드)
|
||||||
|
|
||||||
### 3.1 진입점 — `examples/main.go`
|
### 3.1 진입점 — `lib/main.go`
|
||||||
- 프로젝트의 유일한 `main()` 함수. `var port = ":8080"`을 정의하고 있으며, 기본 상태에서는 `jsonexample.JsonParsingExample()`만 호출합니다.
|
- 프로젝트의 유일한 `main()` 함수. `var port = ":8080"`을 정의하고 있으며, 기본 상태에서는 `jsonexample.JsonParsingExample()`만 호출합니다.
|
||||||
- gRPC 예제를 실행하려면 README.md 안내에 따라 `main()` 내부를 수동으로 편집해 `grpcSample()`을 호출하도록 바꿔야 합니다(미사용 import 오류 방지를 위해 `jsonexample` import를 주석 처리해야 함). 즉 **하나의 코드베이스 안에서 학습 단계별로 진입점을 수동 전환하는 방식**으로 설계되어 있습니다.
|
- gRPC 예제를 실행하려면 README.md 안내에 따라 `main()` 내부를 수동으로 편집해 `grpcSample()`을 호출하도록 바꿔야 합니다(미사용 import 오류 방지를 위해 `jsonexample` import를 주석 처리해야 함). 즉 **하나의 코드베이스 안에서 학습 단계별로 진입점을 수동 전환하는 방식**으로 설계되어 있습니다.
|
||||||
- `grpcSample()` 함수는 `entity.ServerRun(port)`를 고루틴으로 백그라운드 실행한 뒤 1초 대기 후 `entity.ClientRun(...)`을 호출해, 같은 프로세스 안에서 서버·클라이언트가 통신하는 데모를 구성합니다.
|
- `grpcSample()` 함수는 `entity.ServerRun(port)`를 고루틴으로 백그라운드 실행한 뒤 1초 대기 후 `entity.ClientRun(...)`을 호출해, 같은 프로세스 안에서 서버·클라이언트가 통신하는 데모를 구성합니다.
|
||||||
|
|
||||||
### 3.2 JSON 파싱 예제 — `examples/jsonexample/json_parser.go`
|
### 3.2 JSON 파싱 예제 — `lib/jsonexample/json_parser.go`
|
||||||
- `encoding/json` 표준 라이브러리를 이용해 (1) `map[string]interface{}` ↔ JSON 문자열 변환, (2) 구조체(`Person`) ↔ JSON 변환의 마샬링/언마샬링을 시연합니다.
|
- `encoding/json` 표준 라이브러리를 이용해 (1) `map[string]interface{}` ↔ JSON 문자열 변환, (2) 구조체(`Person`) ↔ JSON 변환의 마샬링/언마샬링을 시연합니다.
|
||||||
- 외부 의존성 없이 표준 라이브러리만 사용하는 가장 단순한 예제로, 커리큘럼의 1단계 역할을 합니다.
|
- 외부 의존성 없이 표준 라이브러리만 사용하는 가장 단순한 예제로, 커리큘럼의 1단계 역할을 합니다.
|
||||||
|
|
||||||
### 3.3 HTTP 서버 예제 — `examples/httpentity/`
|
### 3.3 HTTP 서버 예제 — `lib/httpentity/`
|
||||||
- `server.go`는 `gin-gonic/gin`을 이용한 REST API 서버(정적 파일 서빙 + `/api/randomNumber`, `/api/randomPassword`, `/api/randomDate` 라우트) 초안이 **전체 주석 처리**된 상태로만 존재합니다. 즉 코드는 작성되어 있으나 활성화되지 않은 미완성/보류 상태입니다.
|
- `server.go`는 `gin-gonic/gin`을 이용한 REST API 서버(정적 파일 서빙 + `/api/randomNumber`, `/api/randomPassword`, `/api/randomDate` 라우트) 초안이 **전체 주석 처리**된 상태로만 존재합니다. 즉 코드는 작성되어 있으나 활성화되지 않은 미완성/보류 상태입니다.
|
||||||
- `client.go`는 `package httpentity` 선언 한 줄만 있는 빈 파일입니다.
|
- `client.go`는 `package httpentity` 선언 한 줄만 있는 빈 파일입니다.
|
||||||
- `go.mod`에는 `gin-gonic/gin` 의존성이 여전히 선언되어 있어, 이 파트가 완전히 폐기된 것이 아니라 추후 재개를 염두에 둔 진행 중(work-in-progress) 상태로 보입니다.
|
- `go.mod`에는 `gin-gonic/gin` 의존성이 여전히 선언되어 있어, 이 파트가 완전히 폐기된 것이 아니라 추후 재개를 염두에 둔 진행 중(work-in-progress) 상태로 보입니다.
|
||||||
@@ -72,21 +72,21 @@ grpccanary/
|
|||||||
- `option go_package = "./protoapi/;protoapi"`로 지정되어 있어, `protoc` 컴파일 시 `protoapi/` 디렉토리에 Go 패키지 `protoapi`가 생성됩니다.
|
- `option go_package = "./protoapi/;protoapi"`로 지정되어 있어, `protoc` 컴파일 시 `protoapi/` 디렉토리에 Go 패키지 `protoapi`가 생성됩니다.
|
||||||
- 이미 컴파일된 stub(`protoapi/protoapi.pb.go`, `protoapi/protoapi_grpc.pb.go`)이 저장소에 커밋되어 있어 `protoc` 재설치 없이 바로 빌드/실행이 가능합니다.
|
- 이미 컴파일된 stub(`protoapi/protoapi.pb.go`, `protoapi/protoapi_grpc.pb.go`)이 저장소에 커밋되어 있어 `protoc` 재설치 없이 바로 빌드/실행이 가능합니다.
|
||||||
|
|
||||||
### 3.5 gRPC 서버 구현 — `examples/grpcentity/server.go`
|
### 3.5 gRPC 서버 구현 — `lib/grpcentity/server.go`
|
||||||
- `RandomServer` 구조체가 `protoapi.UnimplementedRandomServer`를 임베딩하여 3개 RPC 메서드(`GetDate`, `GetRandom`, `GetRandomPass`)를 구현합니다.
|
- `RandomServer` 구조체가 `protoapi.UnimplementedRandomServer`를 임베딩하여 3개 RPC 메서드(`GetDate`, `GetRandom`, `GetRandomPass`)를 구현합니다.
|
||||||
- `getString(len int64)`은 ASCII 코드 `!`(33)부터 94개 범위 내에서 문자를 뽑아 임의 문자열(비밀번호)을 생성하는 헬퍼입니다.
|
- `getString(len int64)`은 ASCII 코드 `!`(33)부터 94개 범위 내에서 문자를 뽑아 임의 문자열(비밀번호)을 생성하는 헬퍼입니다.
|
||||||
- `ServerRun(addr string)`이 `grpc.NewServer()`로 서버를 만들고 `reflection.Register(server)`로 gRPC reflection(예: `grpcurl` 같은 외부 CLI 디버깅 도구 지원)을 활성화한 뒤 TCP 포트를 리슨합니다.
|
- `ServerRun(addr string)`이 `grpc.NewServer()`로 서버를 만들고 `reflection.Register(server)`로 gRPC reflection(예: `grpcurl` 같은 외부 CLI 디버깅 도구 지원)을 활성화한 뒤 TCP 포트를 리슨합니다.
|
||||||
- **주의(코드상 특이점)**: `ServerRun`은 인자로 받은 `addr`을 실제로 사용하지 않고 패키지 전역 변수 `port = ":8080"`으로 리슨합니다(`net.Listen("tcp", port)`). 따라서 현재 코드는 항상 `:8080`에서만 동작하며, 호출부에서 다른 포트를 넘겨도 무시됩니다.
|
- **주의(코드상 특이점)**: `ServerRun`은 인자로 받은 `addr`을 실제로 사용하지 않고 패키지 전역 변수 `port = ":8080"`으로 리슨합니다(`net.Listen("tcp", port)`). 따라서 현재 코드는 항상 `:8080`에서만 동작하며, 호출부에서 다른 포트를 넘겨도 무시됩니다.
|
||||||
- `rand.Seed(r.GetSeed())`(패키지 전역 시드 설정, Go 1.20+에서는 deprecated)와 `rand.NewSource`를 혼용하고 있어 스레드 안전성이나 API 일관성 측면에서 다소 오래된 패턴을 보입니다(학습용 예제이므로 의도된 단순화로 판단됨).
|
- `rand.Seed(r.GetSeed())`(패키지 전역 시드 설정, Go 1.20+에서는 deprecated)와 `rand.NewSource`를 혼용하고 있어 스레드 안전성이나 API 일관성 측면에서 다소 오래된 패턴을 보입니다(학습용 예제이므로 의도된 단순화로 판단됨).
|
||||||
|
|
||||||
### 3.6 gRPC 클라이언트 구현 — `examples/grpcentity/client.go`
|
### 3.6 gRPC 클라이언트 구현 — `lib/grpcentity/client.go`
|
||||||
- `grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))`로 평문(TLS 미적용) 채널을 생성합니다(로컬 테스트 목적).
|
- `grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))`로 평문(TLS 미적용) 채널을 생성합니다(로컬 테스트 목적).
|
||||||
- `AskingDateTime`, `AskPass`, `AskRandom` 세 개의 래퍼 함수가 각각 대응하는 RPC를 호출합니다.
|
- `AskingDateTime`, `AskPass`, `AskRandom` 세 개의 래퍼 함수가 각각 대응하는 RPC를 호출합니다.
|
||||||
- `ClientRun(addr)`이 실행 엔트리포인트로, 날짜/시간 조회 1회, 비밀번호 생성 1회, 서로 다른 파라미터로 난수 생성 2회를 순차 호출하며 결과를 표준 출력으로 출력합니다.
|
- `ClientRun(addr)`이 실행 엔트리포인트로, 날짜/시간 조회 1회, 비밀번호 생성 1회, 서로 다른 파라미터로 난수 생성 2회를 순차 호출하며 결과를 표준 출력으로 출력합니다.
|
||||||
|
|
||||||
### 3.7 문서 자료
|
### 3.7 문서 자료
|
||||||
- **`README.md`(루트)**: 이야기체(스타트업 개발자 '민우'의 사례)로 gRPC 도입 배경(REST/JSON의 한계, Protobuf 계약, HTTP/2)을 설명한 뒤, Go 버전 요구사항(1.25.4+), 의존성 설치, `main.go` 수동 편집 방법, 실행 명령(`go run ./examples`), 기대 출력 예시, 트러블슈팅(포트 충돌, 모듈 로드 오류)까지 안내하는 실행 가이드로 구성되어 있습니다.
|
- **`README.md`(루트)**: 이야기체(스타트업 개발자 '민우'의 사례)로 gRPC 도입 배경(REST/JSON의 한계, Protobuf 계약, HTTP/2)을 설명한 뒤, Go 버전 요구사항(1.25.4+), 의존성 설치, `main.go` 수동 편집 방법, 실행 명령(`go run ./examples`), 기대 출력 예시, 트러블슈팅(포트 충돌, 모듈 로드 오류)까지 안내하는 실행 가이드로 구성되어 있습니다.
|
||||||
- **`examples/grpcentity/README.md`**: `.proto` 파일 문법 요소별 상세 해설, `protoc`/`protoc-gen-go`/`protoc-gen-go-grpc` 설치 및 컴파일 절차, 서버·클라이언트 코드의 구현 단계별 설명을 담은 심화 가이드입니다.
|
- **`lib/grpcentity/README.md`**: `.proto` 파일 문법 요소별 상세 해설, `protoc`/`protoc-gen-go`/`protoc-gen-go-grpc` 설치 및 컴파일 절차, 서버·클라이언트 코드의 구현 단계별 설명을 담은 심화 가이드입니다.
|
||||||
- **`docs/Working with JSON/`**: JSON 관련 별도 학습 자료(영/한 병기)가 준비되어 있으나, 루트 README와 직접 링크되어 있지는 않습니다.
|
- **`docs/Working with JSON/`**: JSON 관련 별도 학습 자료(영/한 병기)가 준비되어 있으나, 루트 README와 직접 링크되어 있지는 않습니다.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -101,7 +101,7 @@ grpccanary/
|
|||||||
- **`.mam/`**: 위 인프라의 런타임 상태 저장소로, `jobs/`(작업 레지스트리 및 브리프 파일), `agent-sessions.yaml`/`.db`(세션 상태), `agent_homes/`(에이전트별 메모리), `delegate_job_logs/`(위임 감사 로그)를 포함합니다. 이번 작업 브리프(`.mam/jobs/702ea1d8/brief.md`) 역시 이 구조를 통해 전달되었습니다.
|
- **`.mam/`**: 위 인프라의 런타임 상태 저장소로, `jobs/`(작업 레지스트리 및 브리프 파일), `agent-sessions.yaml`/`.db`(세션 상태), `agent_homes/`(에이전트별 메모리), `delegate_job_logs/`(위임 감사 로그)를 포함합니다. 이번 작업 브리프(`.mam/jobs/702ea1d8/brief.md`) 역시 이 구조를 통해 전달되었습니다.
|
||||||
- **`scripts/generate-env.sh`, `.env.example`**: 이 인프라가 사용하는 MQTT 브로커 접속 정보, 경로 설정 등을 `.env`로 초기화하는 헬퍼입니다. 실제 비밀 값은 `.env`(git-ignored)에만 두고 `.env.example`에는 플레이스홀더만 커밋하도록 설계되어 있습니다.
|
- **`scripts/generate-env.sh`, `.env.example`**: 이 인프라가 사용하는 MQTT 브로커 접속 정보, 경로 설정 등을 `.env`로 초기화하는 헬퍼입니다. 실제 비밀 값은 `.env`(git-ignored)에만 두고 `.env.example`에는 플레이스홀더만 커밋하도록 설계되어 있습니다.
|
||||||
|
|
||||||
**참고**: 새로 추가된 `.gitignore`는 `.agents/`, `.mam/`, `.env`, `AGENTS.md` 등을 앞으로 git 추적 대상에서 제외하도록 지정하고 있습니다. 다만 `git log`를 보면 `AGENTS.md`, `examples/grpcentity/README.md` 등은 과거 커밋(`init 251117`, `update 260609`, 이후 docs 커밋들)에서 이미 저장소에 커밋되어 있으므로, 이번 `.gitignore` 추가는 향후 신규/변경 파일이 실수로 다시 커밋되는 것을 막기 위한 조치로 보입니다(기존에 추적 중인 파일을 소급 제외하지는 않음).
|
**참고**: 새로 추가된 `.gitignore`는 `.agents/`, `.mam/`, `.env`, `AGENTS.md` 등을 앞으로 git 추적 대상에서 제외하도록 지정하고 있습니다. 다만 `git log`를 보면 `AGENTS.md`, `lib/grpcentity/README.md` 등은 과거 커밋(`init 251117`, `update 260609`, 이후 docs 커밋들)에서 이미 저장소에 커밋되어 있으므로, 이번 `.gitignore` 추가는 향후 신규/변경 파일이 실수로 다시 커밋되는 것을 막기 위한 조치로 보입니다(기존에 추적 중인 파일을 소급 제외하지는 않음).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -117,16 +117,16 @@ go mod download # 의존성 다운로드
|
|||||||
```bash
|
```bash
|
||||||
go run ./examples
|
go run ./examples
|
||||||
```
|
```
|
||||||
`examples/main.go`가 기본적으로 `jsonexample.JsonParsingExample()`만 호출하므로, 별도 수정 없이 바로 JSON 마샬링/언마샬링 결과가 콘솔에 출력됩니다.
|
`lib/main.go`가 기본적으로 `jsonexample.JsonParsingExample()`만 호출하므로, 별도 수정 없이 바로 JSON 마샬링/언마샬링 결과가 콘솔에 출력됩니다.
|
||||||
|
|
||||||
### 5.3 gRPC 예제 실행 (수동 편집 필요)
|
### 5.3 gRPC 예제 실행 (수동 편집 필요)
|
||||||
1. `examples/main.go`를 열어 `jsonexample` import를 주석 처리하고 `main()` 안에서 `grpcSample()`을 호출하도록 변경.
|
1. `lib/main.go`를 열어 `jsonexample` import를 주석 처리하고 `main()` 안에서 `grpcSample()`을 호출하도록 변경.
|
||||||
2. 저장 후 실행:
|
2. 저장 후 실행:
|
||||||
```bash
|
```bash
|
||||||
go run ./examples
|
go run ./examples
|
||||||
```
|
```
|
||||||
3. 내부적으로 `:8080` 포트에서 gRPC 서버(고루틴)가 기동되고, 1초 후 클라이언트가 `GetDate`, `GetRandomPass`, `GetRandom`(2회) 순으로 RPC를 호출하며 결과를 출력합니다.
|
3. 내부적으로 `:8080` 포트에서 gRPC 서버(고루틴)가 기동되고, 1초 후 클라이언트가 `GetDate`, `GetRandomPass`, `GetRandom`(2회) 순으로 RPC를 호출하며 결과를 출력합니다.
|
||||||
4. 포트 충돌 시(`bind: address already in use`) `examples/grpcentity/server.go`의 `port` 전역 변수를 변경해야 합니다(3.5절에서 언급했듯 `ServerRun`의 `addr` 인자는 무시되므로, 포트 변경은 이 전역 변수 수정으로만 가능).
|
4. 포트 충돌 시(`bind: address already in use`) `lib/grpcentity/server.go`의 `port` 전역 변수를 변경해야 합니다(3.5절에서 언급했듯 `ServerRun`의 `addr` 인자는 무시되므로, 포트 변경은 이 전역 변수 수정으로만 가능).
|
||||||
|
|
||||||
### 5.4 HTTP 예제
|
### 5.4 HTTP 예제
|
||||||
`httpentity` 패키지는 서버 로직 전체가 주석 처리되어 있고 클라이언트 파일은 비어 있어, 현재 상태로는 실행 가능한 산출물이 없습니다. 향후 주석을 해제하고 `main.go`에 호출부를 추가해야 실습이 가능합니다.
|
`httpentity` 패키지는 서버 로직 전체가 주석 처리되어 있고 클라이언트 파일은 비어 있어, 현재 상태로는 실행 가능한 산출물이 없습니다. 향후 주석을 해제하고 `main.go`에 호출부를 추가해야 실습이 가능합니다.
|
||||||
@@ -137,13 +137,13 @@ go run ./examples
|
|||||||
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \
|
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \
|
||||||
--go-grpc_opt=paths=source_relative protoapi.proto
|
--go-grpc_opt=paths=source_relative protoapi.proto
|
||||||
```
|
```
|
||||||
사전에 `protoc`, `protoc-gen-go`, `protoc-gen-go-grpc`가 설치되어 있어야 합니다(설치 방법은 `examples/grpcentity/README.md` 참고).
|
사전에 `protoc`, `protoc-gen-go`, `protoc-gen-go-grpc`가 설치되어 있어야 합니다(설치 방법은 `lib/grpcentity/README.md` 참고).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. 주요 관찰 사항 및 특이점
|
## 6. 주요 관찰 사항 및 특이점
|
||||||
|
|
||||||
1. **단일 진입점, 수동 전환 방식**: `examples/main.go`가 유일한 실행 지점이며, 학습 단계(JSON/HTTP/gRPC)를 전환하려면 코드를 직접 편집해야 합니다. 각 예제를 독립적으로 실행할 수 있는 별도 커맨드나 플래그는 없습니다.
|
1. **단일 진입점, 수동 전환 방식**: `lib/main.go`가 유일한 실행 지점이며, 학습 단계(JSON/HTTP/gRPC)를 전환하려면 코드를 직접 편집해야 합니다. 각 예제를 독립적으로 실행할 수 있는 별도 커맨드나 플래그는 없습니다.
|
||||||
2. **`ServerRun(addr)`의 `addr` 인자 미사용**: gRPC 서버는 전달받은 인자 대신 패키지 전역 `port` 변수로 리슨하므로, 함수 시그니처와 실제 동작이 일치하지 않는 잠재적 혼동 요소입니다.
|
2. **`ServerRun(addr)`의 `addr` 인자 미사용**: gRPC 서버는 전달받은 인자 대신 패키지 전역 `port` 변수로 리슨하므로, 함수 시그니처와 실제 동작이 일치하지 않는 잠재적 혼동 요소입니다.
|
||||||
3. **HTTP 파트 미완성**: `gin` 의존성은 `go.mod`에 존재하지만 실제 코드는 비활성 상태로, 커리큘럼상 "다음 실습 예정" 단계로 보입니다.
|
3. **HTTP 파트 미완성**: `gin` 의존성은 `go.mod`에 존재하지만 실제 코드는 비활성 상태로, 커리큘럼상 "다음 실습 예정" 단계로 보입니다.
|
||||||
4. **테스트 부재**: 저장소 전체에 자동화된 테스트(`*_test.go`)가 없어, 코드 정상 동작 여부는 수동 실행(`go run`)과 콘솔 출력 확인에 의존합니다. `go build ./...`, `go vet ./...`는 통과합니다.
|
4. **테스트 부재**: 저장소 전체에 자동화된 테스트(`*_test.go`)가 없어, 코드 정상 동작 여부는 수동 실행(`go run`)과 콘솔 출력 확인에 의존합니다. `go build ./...`, `go vet ./...`는 통과합니다.
|
||||||
|
|||||||
Reference in New Issue
Block a user