refactor: migrate lib/grpcentity to lib/grpc/basic and update path references
This commit is contained in:
@@ -29,7 +29,8 @@ grpccanary/
|
||||
│ ├── main.go # 학습 예제 통합 실행 진입점 (수동 전환)
|
||||
│ ├── jsonexample/ # 1단계: JSON 데이터 다루기 실습 예제
|
||||
│ ├── httpentity/ # 2단계: HTTP & Gin 웹 서버 실습 예제 (WIP)
|
||||
│ └── grpcentity/ # 3단계: gRPC 통신 구현 실습 예제 (서버/클라이언트 데모)
|
||||
│ └── grpc/
|
||||
│ └── basic/ # 3단계: gRPC 통신 구현 실습 예제 (서버/클라이언트 데모)
|
||||
│ ├── protoapi.proto # gRPC 인터페이스 정의서 (IDL)
|
||||
│ └── protoapi/ # protoc로 컴파일 생성된 Go Stub 코드
|
||||
└── docs/
|
||||
@@ -45,7 +46,7 @@ grpccanary/
|
||||
### 2단계: HTTP & Gin 웹 서버 (`lib/httpentity`)
|
||||
* 대중적인 Go 웹 프레임워크 `gin-gonic`을 활용해 RESTful API 사양을 구축하는 방법을 이해합니다. (현재 주석 해제 후 실습하도록 설계된 Work-in-Progress 단계)
|
||||
|
||||
### 3단계: gRPC 통신 구현 (`lib/grpcentity`)
|
||||
### 3단계: gRPC 통신 구현 (`lib/grpc/basic`)
|
||||
* `.proto` 정의를 바탕으로 통신 스키마 계약을 강제하고, Go 언어로 gRPC 서버를 띄워 클라이언트가 날짜/시간, 무작위 비밀번호 및 정수 데이터를 실시간 원격 호출로 송수신하는 분산 통신 기초를 학습합니다.
|
||||
* `.proto` 정의를 바탕으로 통신 스키마 계약을 강제하고, Go 언어로 gRPC 서버를 띄워 클라이언트가 날짜/시간, 무작위 비밀번호 및 정수 데이터를 실시간 원격 호출로 송수신하는 분산 통신 기초를 학습합니다.
|
||||
|
||||
@@ -106,4 +107,4 @@ Sensing Update Message: Sensing data updated successfully for device sensor-room
|
||||
* **[docs/JSON.md](docs/JSON.md)**: 1단계 JSON 데이터 다루기 상세 학습 가이드
|
||||
* **[docs/HTTP.md](docs/HTTP.md)**: 2단계 HTTP & Gin 웹 프레임워크 상세 학습 가이드
|
||||
* **[docs/GRPC.md](docs/GRPC.md)**: 3단계 gRPC & Protobuf 상세 학습 가이드 (컴파일 절차 및 소스코드 구현체 분석 포함)
|
||||
* **[lib/grpcentity/README.md](lib/grpcentity/README.md)**: gRPC 실습 디렉토리 안내 및 `docs/GRPC.md` 심화 가이드로의 링크
|
||||
* **[lib/grpc/basic/README.md](lib/grpc/basic/README.md)**: gRPC 실습 디렉토리 안내 및 `docs/GRPC.md` 심화 가이드로의 링크
|
||||
|
||||
+9
-9
@@ -83,7 +83,7 @@ gRPC는 HTTP/2를 기반으로 구축된 구글의 고성능 오픈소스 원격
|
||||
|
||||
### 3.4 명세서 소스코드 및 구체적 분석
|
||||
|
||||
실습 디렉토리 내에 선언된 [protoapi.proto](../lib/grpcentity/protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다.
|
||||
실습 디렉토리 내에 선언된 [protoapi.proto](../lib/grpc/basic/protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다.
|
||||
|
||||
※ 이 코드는 기본 Unary RPC 3종만 발췌한 것이며, 전체 스펙(스트리밍 4종 포함)은 §7.1에서 이어집니다.
|
||||
|
||||
@@ -178,7 +178,7 @@ gRPC 빌드 및 코드 생성 환경을 구축하기 위해 사용되는 세 가
|
||||
작성된 스키마 명세를 빌드하여 Go 소스코드를 생성하기 위해 다음 명령어를 구동합니다:
|
||||
```bash
|
||||
# 해당 실습 디렉터리로 이동 후 컴파일 실행
|
||||
cd lib/grpcentity
|
||||
cd lib/grpc/basic
|
||||
protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||
```
|
||||
|
||||
@@ -189,7 +189,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||
|
||||
**Go 패키지 지정 옵션과의 결합 규칙**:
|
||||
해당 출력 경로 옵션들은 단독으로 파일의 최종 위치를 고정하지 않습니다. 컴파일러는 지정된 기준 경로(예: `.`)에 `.proto` 스펙 내부의 `option go_package = "./protoapi;protoapi"` 설정값을 조합하여 최종 디렉터리 경로를 생성합니다.
|
||||
이에 따라 **컴파일 대상 디렉터리(`.`)**와 **상세 패키지 주소(`./protoapi`)**가 결합되어 `lib/grpcentity/protoapi/` 경로가 자동 생성되며, 그 하위에 다음 소스코드들이 정상 배치됩니다:
|
||||
이에 따라 **컴파일 대상 디렉터리(`.`)**와 **상세 패키지 주소(`./protoapi`)**가 결합되어 `lib/grpc/basic/protoapi/` 경로가 자동 생성되며, 그 하위에 다음 소스코드들이 정상 배치됩니다:
|
||||
* `protoapi.pb.go`: 명세에 정의된 메시지(Message) 규격을 Go 구조체로 변환한 파일입니다.
|
||||
* `protoapi_grpc.pb.go`: 클라이언트와 서버 통신을 위한 원격 호출(Service) 규격을 구현한 파일입니다.
|
||||
|
||||
@@ -199,7 +199,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||
|
||||
컴파일러를 통해 통신을 위한 스터브(Stub) 코드가 확보되었으므로, 이를 기반으로 서버와 클라이언트의 비즈니스 로직을 연결하는 상세 코드를 검토합니다.
|
||||
|
||||
### 5.1 gRPC 서버 구현 분석 ([server.go](../lib/grpcentity/server.go))
|
||||
### 5.1 gRPC 서버 구현 분석 ([server.go](../lib/grpc/basic/server.go))
|
||||
|
||||
* **서버 서비스 인터페이스 매핑 구조체 (`IoTServer`)**:
|
||||
```go
|
||||
@@ -243,7 +243,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||
* **쉬운 설명**: `:8080` 포트로 통하는 소켓(전화선)을 개통하고, 기기들의 전화(접속 및 호출)가 오기를 기다리며 대기 상태로 들어가는 서버 구동 시작점입니다.
|
||||
* **상세 설명**: 지정된 포트(기본 포트 `:8080`)의 TCP 소켓 포트를 활성화하고, 클라이언트의 접속 및 RPC 서비스 호출에 대해 지속적으로 대기하는 리스너 구동의 진입점입니다.
|
||||
|
||||
### 5.2 gRPC 클라이언트 구현 분석 ([client.go](../lib/grpcentity/client.go))
|
||||
### 5.2 gRPC 클라이언트 구현 분석 ([client.go](../lib/grpc/basic/client.go))
|
||||
|
||||
* **원격 서비스 클라이언트 기동 (`NewIoTServiceClient`)**:
|
||||
```go
|
||||
@@ -317,7 +317,7 @@ message DownloadRequest {
|
||||
```
|
||||
* **설계 포인트**: `stream` 키워드가 들어간 위치에 주목합니다. `UploadFile`은 입력에 `stream`이 붙어 클라이언트 스트리밍을, `DownloadFile`은 반환(returns)에 `stream`이 붙어 서버 스트리밍 채널을 개설합니다.
|
||||
|
||||
### 6.2 서버 저장 및 송수신 구현 ([server.go](../lib/grpcentity/server.go))
|
||||
### 6.2 서버 저장 및 송수신 구현 ([server.go](../lib/grpc/basic/server.go))
|
||||
인메모리 파일 저장소(`fileStore`)를 구현하고 목록 조회(`ListFiles`) 및 서버 다운로드 스트리밍(`DownloadFile`) 핸들러를 정의합니다:
|
||||
|
||||
```go
|
||||
@@ -427,7 +427,7 @@ func (IoTServer) DownloadFile(r *protoapi.DownloadRequest, stream protoapi.IoTSe
|
||||
* **목록 조회**: 동시 접근 보호(Race condition 방지)를 위해 읽기 전용 락(`RLock`)을 획득한 후 인메모리 맵을 순회하며 메타데이터 구조체 목록을 집계해 반환합니다.
|
||||
* **파일 다운로드**: 대상 파일 쿼리 실패 시 gRPC 표준 에러(`codes.NotFound`)를 반환합니다. 검증 통과 시 루프 내에서 가상 윈도우 슬라이싱을 집행해 청크 구조체를 구성하고, `stream.Send()`로 직렬화 패킷을 클라이언트 버퍼 큐에 기입합니다.
|
||||
|
||||
### 6.3 클라이언트 송수신 기동 ([client.go](../lib/grpcentity/client.go))
|
||||
### 6.3 클라이언트 송수신 기동 ([client.go](../lib/grpc/basic/client.go))
|
||||
클라이언트는 업로드에 성공한 뒤, 서버에 파일 목록 조회를 요구하고, 다운로드 스트림을 개설해 조각 데이터를 재조립하여 무결성을 검사합니다.
|
||||
|
||||
```go
|
||||
@@ -516,7 +516,7 @@ message AlertMessage {
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 서버 사이드 구독자 관리 및 발행 구현 ([server.go](../lib/grpcentity/server.go))
|
||||
#### 2. 서버 사이드 구독자 관리 및 발행 구현 ([server.go](../lib/grpc/basic/server.go))
|
||||
서버는 구독을 신청한 클라이언트들에게 메시지를 안전하게 분배하기 위해 스레드 세이프 맵과 고루틴 채널(`chan`) 구조를 구성합니다:
|
||||
|
||||
```go
|
||||
@@ -586,7 +586,7 @@ func (IoTServer) SubscribeAlerts(r *protoapi.AlertSubscription, stream protoapi.
|
||||
* **구독 신청**: `SubscribeAlerts` 엔드포인트는 호출과 동시에 전용 Go 비동기 버퍼 채널을 생성하고 전역 가입 맵에 등록합니다. `stream.Context().Done()` 채널 수신이나 스트림 유실 이벤트가 포착되기 전까지 루프 대기 상태를 안전하게 고정합니다.
|
||||
* **경보 발행**: 동시성 경쟁 방지 락(`subMu.Lock()`) 임계 구역 내에서 연결된 모든 채널에 데이터를 `select-default` 논블로킹 패턴으로 분배 기입하여, 특정 클라이언트의 수신 병목이 서버 전체 성능에 미치는 파급 효과를 예방합니다.
|
||||
|
||||
#### 3. 클라이언트 비동기 청취 구현 ([client.go](../lib/grpcentity/client.go))
|
||||
#### 3. 클라이언트 비동기 청취 구현 ([client.go](../lib/grpc/basic/client.go))
|
||||
클라이언트는 메인 흐름을 방해하지 않고 알림을 백그라운드에서 실시간으로 대기 청취할 수 있도록 별도의 독자적인 비동기 고루틴 구조로 가동합니다.
|
||||
|
||||
```go
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# lib/grpcentity 실습 설명서
|
||||
# lib/grpc/basic 실습 설명서
|
||||
|
||||
본 디렉토리는 Go 언어를 활용한 gRPC 서버 및 클라이언트 실습 예제를 포함하고 있습니다.
|
||||
|
||||
## 📖 실습 상세 분석 및 가이드 안내
|
||||
|
||||
학습의 일관성을 위해, 이 실습의 상세 분석 및 개념 명세는 통합 교재의 gRPC 심화 가이드인 **[docs/GRPC.md](../../docs/GRPC.md)**로 모듈화되어 있습니다. 전체 학습 로드맵은 [docs/MANUSCRIPT.md](../../docs/MANUSCRIPT.md)를 참고하십시오.
|
||||
학습의 일관성을 위해, 이 실습의 상세 분석 및 개념 명세는 통합 교재의 gRPC 심화 가이드인 **[docs/GRPC.md](../../../docs/GRPC.md)**로 모듈화되어 있습니다. 전체 학습 로드맵은 [docs/MANUSCRIPT.md](../../../docs/MANUSCRIPT.md)를 참고하십시오.
|
||||
|
||||
[docs/GRPC.md](../../docs/GRPC.md) 문서에서 다음 내용을 참고하실 수 있습니다:
|
||||
[docs/GRPC.md](../../../docs/GRPC.md) 문서에서 다음 내용을 참고하실 수 있습니다:
|
||||
* **IDL ([protoapi.proto](./protoapi.proto)) 명세 및 필드 분석**
|
||||
* **Go에서의 `protoc` 설치 및 Stub 파일 컴파일 방법**
|
||||
* **gRPC 서버 코드 ([server.go](./server.go)) 구현 상세 분석**
|
||||
@@ -1,9 +1,9 @@
|
||||
package entity
|
||||
package basic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"grpccanary/lib/grpcentity/protoapi"
|
||||
"grpccanary/lib/grpc/basic/protoapi"
|
||||
"io"
|
||||
"math/rand"
|
||||
"time"
|
||||
@@ -207,11 +207,13 @@ func ClientRun(addr string) {
|
||||
|
||||
// 7단계: 임계값 초과 온습도 전송을 통한 Pub/Sub 실시간 알림 유발 시뮬레이션
|
||||
fmt.Println("Sending abnormal high-temperature sensing data (45.8°C)...")
|
||||
|
||||
alertRes, err := AskUpdateSensingData(context.Background(), client, "sensor-room-01", 45.8, 60.1)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Abnormal Sensing Update Success:", alertRes.Success)
|
||||
// 알림 이벤트가 비동기로 화면에 출력될 시간을 확보하기 위해 100ms 대기
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v5.27.2
|
||||
// protoc v3.21.12
|
||||
// source: protoapi.proto
|
||||
|
||||
package protoapi
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v5.27.2
|
||||
// - protoc v3.21.12
|
||||
// source: protoapi.proto
|
||||
|
||||
package protoapi
|
||||
@@ -1,9 +1,9 @@
|
||||
package entity
|
||||
package basic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"grpccanary/lib/grpcentity/protoapi"
|
||||
"grpccanary/lib/grpc/basic/protoapi"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
+3
-3
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
entity "grpccanary/lib/grpcentity"
|
||||
"grpccanary/lib/grpc/basic"
|
||||
"grpccanary/lib/jsonexample"
|
||||
"time"
|
||||
)
|
||||
@@ -21,11 +21,11 @@ func grpcSample() {
|
||||
fmt.Println("--- starting gRPC IoT Simulation ---")
|
||||
|
||||
// 1. gRPC 서버를 백그라운드 고루틴으로 구동
|
||||
go entity.ServerRun(port)
|
||||
go basic.ServerRun(port)
|
||||
|
||||
// 2. 서버 포트가 바인딩되어 통신 대기 상태에 들어갈 시간을 일시적으로 보장
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// 3. gRPC 클라이언트를 구동하여 원격 프로시저(RPC) 기동 시뮬레이션 집행
|
||||
entity.ClientRun(port)
|
||||
basic.ClientRun(port)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user