diff --git a/README.md b/README.md index 3f423e2..f3c8758 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,13 @@ 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단계: JSON 데이터 다루기 실습 예제 │ ├── httpentity/ # 2단계: HTTP & Gin 웹 서버 실습 예제 (WIP) │ └── grpcentity/ # 3단계: gRPC 통신 구현 실습 예제 (서버/클라이언트 데모) +│ └── protoapi.proto # gRPC 인터페이스 정의서 (IDL) └── docs/ ├── MANUSCRIPT.md # 학습 로드맵 및 각 단계별 심화 가이드로의 안내서 ├── JSON.md # 1단계: JSON 데이터 다루기 상세 가이드 diff --git a/docs/GRPC.md b/docs/GRPC.md index d3eadd1..c2821be 100644 --- a/docs/GRPC.md +++ b/docs/GRPC.md @@ -64,7 +64,7 @@ gRPC는 HTTP/2를 기반으로 구축된 구글의 고성능 오픈소스 원격 ### 3.3 명세서 소스코드 및 구체적 분석 -저장소 루트에 선언된 [protoapi.proto](../protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다. +실습 디렉토리 내에 선언된 [protoapi.proto](../examples/grpcentity/protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다. ```proto syntax = "proto3"; @@ -168,7 +168,7 @@ gRPC 개발 환경을 구축하기 위해 설치하는 세 가지 프로그램 ### 4.3 실제로 번역하기 (컴파일 명령어) 아래 명령어는 컴퓨터에게 **"내가 작성한 `protoapi.proto` 약속 장부를 Go 언어로 번역해서 `protoapi/` 폴더에 가지런히 넣어줘!"** 하고 지시하는 마법의 명령어입니다: ```bash -protoc --go_out=. --go-grpc_out=. protoapi.proto +protoc --go_out=. --go-grpc_out=. examples/grpcentity/protoapi.proto ``` 명령을 실행하고 나면 `protoapi/` 폴더 하위에 다음 두 파일이 기분 좋게 생성됩니다: * `protoapi.pb.go`: 약속 문서에 적은 데이터(Message) 규격들을 Go 구조체로 변환해 놓은 파일입니다. @@ -242,7 +242,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto ## 7. 한 걸음 더 나아가기 (다음 단계) 본 기초 실습을 끝마치셨다면, 함께 학습하는 후배나 동료분들에게 아래와 같은 도전 과제들을 제안해 보십시오: -1. **약속 스펙 확장해 보기**: [protoapi.proto](../protoapi.proto) 파일에 새로운 환경 데이터(예: 미세먼지 수치 `double Dust = 4;`)를 슬쩍 얹어본 뒤, 직접 번역기를 새로 돌리고 Go 소스코드를 고치며 확장해 봅니다. +1. **약속 스펙 확장해 보기**: [protoapi.proto](../examples/grpcentity/protoapi.proto) 파일에 새로운 환경 데이터(예: 미세먼지 수치 `double Dust = 4;`)를 슬쩍 얹어본 뒤, 직접 번역기를 새로 돌리고 Go 소스코드를 고치며 확장해 봅니다. 2. **실전 분산 환경 상상하기**: 수많은 자율 에이전트나 IoT 센서 단말이 하나의 gRPC 중앙 관제 서버로 동시에 데이터를 주고받는 분산 AIoT 멀티 에이전트 인프라로의 아이디어를 고민해 봅니다. --- diff --git a/examples/grpcentity/README.md b/examples/grpcentity/README.md index a77f18f..983a79d 100644 --- a/examples/grpcentity/README.md +++ b/examples/grpcentity/README.md @@ -7,7 +7,7 @@ 학습의 일관성을 위해, 이 실습의 상세 분석 및 개념 명세는 통합 교재의 gRPC 심화 가이드인 **[docs/GRPC.md](../../docs/GRPC.md)**로 모듈화되어 있습니다. 전체 학습 로드맵은 [docs/MANUSCRIPT.md](../../docs/MANUSCRIPT.md)를 참고하십시오. [docs/GRPC.md](../../docs/GRPC.md) 문서에서 다음 내용을 참고하실 수 있습니다: -* **IDL (`protoapi.proto`) 명세 및 필드 분석** +* **IDL ([protoapi.proto](./protoapi.proto)) 명세 및 필드 분석** * **Go에서의 `protoc` 설치 및 Stub 파일 컴파일 방법** * **gRPC 서버 코드 ([server.go](./server.go)) 구현 상세 분석** * **gRPC 클라이언트 코드 ([client.go](./client.go)) 커넥션 및 호출 흐름 분석** diff --git a/protoapi.proto b/examples/grpcentity/protoapi.proto similarity index 100% rename from protoapi.proto rename to examples/grpcentity/protoapi.proto diff --git a/protoapi/protoapi.pb.go b/protoapi/protoapi.pb.go index 2c0092f..c4e592b 100644 --- a/protoapi/protoapi.pb.go +++ b/protoapi/protoapi.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.36.11 // protoc v5.27.2 -// source: protoapi.proto +// source: examples/grpcentity/protoapi.proto package protoapi @@ -32,7 +32,7 @@ type SensingData struct { func (x *SensingData) Reset() { *x = SensingData{} - mi := &file_protoapi_proto_msgTypes[0] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -44,7 +44,7 @@ func (x *SensingData) String() string { func (*SensingData) ProtoMessage() {} func (x *SensingData) ProtoReflect() protoreflect.Message { - mi := &file_protoapi_proto_msgTypes[0] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -57,7 +57,7 @@ func (x *SensingData) ProtoReflect() protoreflect.Message { // Deprecated: Use SensingData.ProtoReflect.Descriptor instead. func (*SensingData) Descriptor() ([]byte, []int) { - return file_protoapi_proto_rawDescGZIP(), []int{0} + return file_examples_grpcentity_protoapi_proto_rawDescGZIP(), []int{0} } func (x *SensingData) GetDeviceId() string { @@ -91,7 +91,7 @@ type SensingResponse struct { func (x *SensingResponse) Reset() { *x = SensingResponse{} - mi := &file_protoapi_proto_msgTypes[1] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -103,7 +103,7 @@ func (x *SensingResponse) String() string { func (*SensingResponse) ProtoMessage() {} func (x *SensingResponse) ProtoReflect() protoreflect.Message { - mi := &file_protoapi_proto_msgTypes[1] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -116,7 +116,7 @@ func (x *SensingResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SensingResponse.ProtoReflect.Descriptor instead. func (*SensingResponse) Descriptor() ([]byte, []int) { - return file_protoapi_proto_rawDescGZIP(), []int{1} + return file_examples_grpcentity_protoapi_proto_rawDescGZIP(), []int{1} } func (x *SensingResponse) GetSuccess() bool { @@ -142,7 +142,7 @@ type DateTime struct { func (x *DateTime) Reset() { *x = DateTime{} - mi := &file_protoapi_proto_msgTypes[2] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -154,7 +154,7 @@ func (x *DateTime) String() string { func (*DateTime) ProtoMessage() {} func (x *DateTime) ProtoReflect() protoreflect.Message { - mi := &file_protoapi_proto_msgTypes[2] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -167,7 +167,7 @@ func (x *DateTime) ProtoReflect() protoreflect.Message { // Deprecated: Use DateTime.ProtoReflect.Descriptor instead. func (*DateTime) Descriptor() ([]byte, []int) { - return file_protoapi_proto_rawDescGZIP(), []int{2} + return file_examples_grpcentity_protoapi_proto_rawDescGZIP(), []int{2} } func (x *DateTime) GetValue() string { @@ -186,7 +186,7 @@ type RequestDateTime struct { func (x *RequestDateTime) Reset() { *x = RequestDateTime{} - mi := &file_protoapi_proto_msgTypes[3] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -198,7 +198,7 @@ func (x *RequestDateTime) String() string { func (*RequestDateTime) ProtoMessage() {} func (x *RequestDateTime) ProtoReflect() protoreflect.Message { - mi := &file_protoapi_proto_msgTypes[3] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -211,7 +211,7 @@ func (x *RequestDateTime) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestDateTime.ProtoReflect.Descriptor instead. func (*RequestDateTime) Descriptor() ([]byte, []int) { - return file_protoapi_proto_rawDescGZIP(), []int{3} + return file_examples_grpcentity_protoapi_proto_rawDescGZIP(), []int{3} } func (x *RequestDateTime) GetValue() string { @@ -231,7 +231,7 @@ type RequestPass struct { func (x *RequestPass) Reset() { *x = RequestPass{} - mi := &file_protoapi_proto_msgTypes[4] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -243,7 +243,7 @@ func (x *RequestPass) String() string { func (*RequestPass) ProtoMessage() {} func (x *RequestPass) ProtoReflect() protoreflect.Message { - mi := &file_protoapi_proto_msgTypes[4] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -256,7 +256,7 @@ func (x *RequestPass) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestPass.ProtoReflect.Descriptor instead. func (*RequestPass) Descriptor() ([]byte, []int) { - return file_protoapi_proto_rawDescGZIP(), []int{4} + return file_examples_grpcentity_protoapi_proto_rawDescGZIP(), []int{4} } func (x *RequestPass) GetSeed() int64 { @@ -282,7 +282,7 @@ type RandomPass struct { func (x *RandomPass) Reset() { *x = RandomPass{} - mi := &file_protoapi_proto_msgTypes[5] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -294,7 +294,7 @@ func (x *RandomPass) String() string { func (*RandomPass) ProtoMessage() {} func (x *RandomPass) ProtoReflect() protoreflect.Message { - mi := &file_protoapi_proto_msgTypes[5] + mi := &file_examples_grpcentity_protoapi_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -307,7 +307,7 @@ func (x *RandomPass) ProtoReflect() protoreflect.Message { // Deprecated: Use RandomPass.ProtoReflect.Descriptor instead. func (*RandomPass) Descriptor() ([]byte, []int) { - return file_protoapi_proto_rawDescGZIP(), []int{5} + return file_examples_grpcentity_protoapi_proto_rawDescGZIP(), []int{5} } func (x *RandomPass) GetPassword() string { @@ -317,11 +317,11 @@ func (x *RandomPass) GetPassword() string { return "" } -var File_protoapi_proto protoreflect.FileDescriptor +var File_examples_grpcentity_protoapi_proto protoreflect.FileDescriptor -const file_protoapi_proto_rawDesc = "" + +const file_examples_grpcentity_protoapi_proto_rawDesc = "" + "\n" + - "\x0eprotoapi.proto\"g\n" + + "\"examples/grpcentity/protoapi.proto\"g\n" + "\vSensingData\x12\x1a\n" + "\bDeviceId\x18\x01 \x01(\tR\bDeviceId\x12 \n" + "\vTemperature\x18\x02 \x01(\x01R\vTemperature\x12\x1a\n" + @@ -346,19 +346,19 @@ const file_protoapi_proto_rawDesc = "" + "\rGetRandomPass\x12\f.RequestPass\x1a\v.RandomPassB\x16Z\x14./protoapi/;protoapib\x06proto3" var ( - file_protoapi_proto_rawDescOnce sync.Once - file_protoapi_proto_rawDescData []byte + file_examples_grpcentity_protoapi_proto_rawDescOnce sync.Once + file_examples_grpcentity_protoapi_proto_rawDescData []byte ) -func file_protoapi_proto_rawDescGZIP() []byte { - file_protoapi_proto_rawDescOnce.Do(func() { - file_protoapi_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_protoapi_proto_rawDesc), len(file_protoapi_proto_rawDesc))) +func file_examples_grpcentity_protoapi_proto_rawDescGZIP() []byte { + file_examples_grpcentity_protoapi_proto_rawDescOnce.Do(func() { + file_examples_grpcentity_protoapi_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_examples_grpcentity_protoapi_proto_rawDesc), len(file_examples_grpcentity_protoapi_proto_rawDesc))) }) - return file_protoapi_proto_rawDescData + return file_examples_grpcentity_protoapi_proto_rawDescData } -var file_protoapi_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_protoapi_proto_goTypes = []any{ +var file_examples_grpcentity_protoapi_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_examples_grpcentity_protoapi_proto_goTypes = []any{ (*SensingData)(nil), // 0: SensingData (*SensingResponse)(nil), // 1: SensingResponse (*DateTime)(nil), // 2: DateTime @@ -366,7 +366,7 @@ var file_protoapi_proto_goTypes = []any{ (*RequestPass)(nil), // 4: RequestPass (*RandomPass)(nil), // 5: RandomPass } -var file_protoapi_proto_depIdxs = []int32{ +var file_examples_grpcentity_protoapi_proto_depIdxs = []int32{ 3, // 0: IoTService.GetDate:input_type -> RequestDateTime 0, // 1: IoTService.UpdateSensingData:input_type -> SensingData 4, // 2: IoTService.GetRandomPass:input_type -> RequestPass @@ -380,26 +380,26 @@ var file_protoapi_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for field type_name } -func init() { file_protoapi_proto_init() } -func file_protoapi_proto_init() { - if File_protoapi_proto != nil { +func init() { file_examples_grpcentity_protoapi_proto_init() } +func file_examples_grpcentity_protoapi_proto_init() { + if File_examples_grpcentity_protoapi_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_protoapi_proto_rawDesc), len(file_protoapi_proto_rawDesc)), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_examples_grpcentity_protoapi_proto_rawDesc), len(file_examples_grpcentity_protoapi_proto_rawDesc)), NumEnums: 0, NumMessages: 6, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_protoapi_proto_goTypes, - DependencyIndexes: file_protoapi_proto_depIdxs, - MessageInfos: file_protoapi_proto_msgTypes, + GoTypes: file_examples_grpcentity_protoapi_proto_goTypes, + DependencyIndexes: file_examples_grpcentity_protoapi_proto_depIdxs, + MessageInfos: file_examples_grpcentity_protoapi_proto_msgTypes, }.Build() - File_protoapi_proto = out.File - file_protoapi_proto_goTypes = nil - file_protoapi_proto_depIdxs = nil + File_examples_grpcentity_protoapi_proto = out.File + file_examples_grpcentity_protoapi_proto_goTypes = nil + file_examples_grpcentity_protoapi_proto_depIdxs = nil } diff --git a/protoapi/protoapi_grpc.pb.go b/protoapi/protoapi_grpc.pb.go index 03d6090..f5384ae 100644 --- a/protoapi/protoapi_grpc.pb.go +++ b/protoapi/protoapi_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.6.2 // - protoc v5.27.2 -// source: protoapi.proto +// source: examples/grpcentity/protoapi.proto package protoapi @@ -193,5 +193,5 @@ var IoTService_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "protoapi.proto", + Metadata: "examples/grpcentity/protoapi.proto", }