refactor: rename examples/ directory to lib/ and update all path references
This commit is contained in:
+9
-9
@@ -82,7 +82,7 @@ gRPC는 HTTP/2를 기반으로 구축된 구글의 고성능 오픈소스 원격
|
||||
|
||||
### 3.4 명세서 소스코드 및 구체적 분석
|
||||
|
||||
실습 디렉토리 내에 선언된 [protoapi.proto](../examples/grpcentity/protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다.
|
||||
실습 디렉토리 내에 선언된 [protoapi.proto](../lib/grpcentity/protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다.
|
||||
|
||||
```proto
|
||||
syntax = "proto3";
|
||||
@@ -175,7 +175,7 @@ gRPC 빌드 및 코드 생성 환경을 구축하기 위해 사용되는 세 가
|
||||
작성된 스키마 명세를 빌드하여 Go 소스코드를 생성하기 위해 다음 명령어를 구동합니다:
|
||||
```bash
|
||||
# 해당 실습 디렉터리로 이동 후 컴파일 실행
|
||||
cd examples/grpcentity
|
||||
cd lib/grpcentity
|
||||
protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||
```
|
||||
|
||||
@@ -186,7 +186,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||
|
||||
**Go 패키지 지정 옵션과의 결합 규칙**:
|
||||
해당 출력 경로 옵션들은 단독으로 파일의 최종 위치를 고정하지 않습니다. 컴파일러는 지정된 기준 경로(예: `.`)에 `.proto` 스펙 내부의 `option go_package = "./protoapi;protoapi"` 설정값을 조합하여 최종 디렉터리 경로를 생성합니다.
|
||||
이에 따라 **컴파일 대상 디렉터리(`.`)**와 **상세 패키지 주소(`./protoapi`)**가 결합되어 `examples/grpcentity/protoapi/` 경로가 자동 생성되며, 그 하위에 다음 소스코드들이 정상 배치됩니다:
|
||||
이에 따라 **컴파일 대상 디렉터리(`.`)**와 **상세 패키지 주소(`./protoapi`)**가 결합되어 `lib/grpcentity/protoapi/` 경로가 자동 생성되며, 그 하위에 다음 소스코드들이 정상 배치됩니다:
|
||||
* `protoapi.pb.go`: 명세에 정의된 메시지(Message) 규격을 Go 구조체로 변환한 파일입니다.
|
||||
* `protoapi_grpc.pb.go`: 클라이언트와 서버 통신을 위한 원격 호출(Service) 규격을 구현한 파일입니다.
|
||||
|
||||
@@ -196,7 +196,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||
|
||||
컴파일러를 통해 통신을 위한 스터브(Stub) 코드가 확보되었으므로, 이를 기반으로 서버와 클라이언트의 비즈니스 로직을 연결하는 상세 코드를 검토합니다.
|
||||
|
||||
### 5.1 gRPC 서버 구현 분석 ([server.go](../examples/grpcentity/server.go))
|
||||
### 5.1 gRPC 서버 구현 분석 ([server.go](../lib/grpcentity/server.go))
|
||||
|
||||
* **서버 서비스 인터페이스 매핑 구조체 (`IoTServer`)**:
|
||||
```go
|
||||
@@ -240,7 +240,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||
* **쉬운 설명**: `:8080` 포트로 통하는 소켓(전화선)을 개통하고, 기기들의 전화(접속 및 호출)가 오기를 기다리며 대기 상태로 들어가는 서버 구동 시작점입니다.
|
||||
* **상세 설명**: 지정된 포트(기본 포트 `:8080`)의 TCP 소켓 포트를 활성화하고, 클라이언트의 접속 및 RPC 서비스 호출에 대해 지속적으로 대기하는 리스너 구동의 진입점입니다.
|
||||
|
||||
### 5.2 gRPC 클라이언트 구현 분석 ([client.go](../examples/grpcentity/client.go))
|
||||
### 5.2 gRPC 클라이언트 구현 분석 ([client.go](../lib/grpcentity/client.go))
|
||||
|
||||
* **원격 서비스 클라이언트 기동 (`NewIoTServiceClient`)**:
|
||||
```go
|
||||
@@ -276,7 +276,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto
|
||||
### 6.1 `bind: address already in use` (네트워크 소켓 포트 충돌)
|
||||
* **발생 원인**: 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` 역시 함께 갱신해 주어야 실제 바인딩 포트 변경이 유효하게 처리됩니다.
|
||||
|
||||
---
|
||||
@@ -324,7 +324,7 @@ message DownloadRequest {
|
||||
```
|
||||
* **설계 포인트**: `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`) 핸들러를 정의합니다:
|
||||
|
||||
```go
|
||||
@@ -392,7 +392,7 @@ func (IoTServer) DownloadFile(r *protoapi.DownloadRequest, stream protoapi.IoTSe
|
||||
* **목록 조회**: 동시 접근 보호(Race condition 방지)를 위해 읽기 전용 락(`RLock`)을 획득한 후 인메모리 맵을 순회하며 메타데이터 구조체 목록을 집계해 반환합니다.
|
||||
* **파일 다운로드**: 대상 파일 쿼리 실패 시 gRPC 표준 에러(`codes.NotFound`)를 반환합니다. 검증 통과 시 루프 내에서 가상 윈도우 슬라이싱을 집행해 청크 구조체를 구성하고, `stream.Send()`로 직렬화 패킷을 클라이언트 버퍼 큐에 기입합니다.
|
||||
|
||||
### 7.3 클라이언트 송수신 기동 ([client.go](../examples/grpcentity/client.go))
|
||||
### 7.3 클라이언트 송수신 기동 ([client.go](../lib/grpcentity/client.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`)으로 조율하여 정상 빌드해 보세요.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user