티스토리 뷰

golang

Protocol Buffers - Golang Tutorial

주먹불끈 2019. 6. 7. 13:49

개요

 

공식 페이지의 Tutorial 따라해보며, Protocol buffers 알아본다.

링크: https://developers.google.com/protocol-buffers/docs/gotutorial

 

매우 간단하게 가지를 것이다.

 

1) 주고 받을 메시지 포맷을 .proto 파일로 정의해본다.

2) protocol buffer compiler (protoc) 이용해서 .pb.go 파일을 생성한다.

3) Go protocol buffer API 이용하여 메시지를 읽고 써본다.

 

 

Protocol Buffer 쓸까?

 

튜토리얼에서 주소록 앱은 사람들의 연락처를 파일에 읽고 쓰게 되며

사람들의 name, ID, email address, contact phone number 담을 것이다.

 

사람들의 정보는 구조체로 표현될 있으며, 이것이 파일에 담길때는 바이트들로 기록될 것이다.

구조화된 데이터를 바이트들로 표현하는게 Serialize 이고,

이런 바이트들을 구조화된 데이터로 만들어주는게 Deserialize 이다.

- 혹은, Marshaling / Unmarshaling 이라고도 부른다.

 

이해를 돕기 위해서 같은 말을 한번 반복해본다.

우리가 프로그래밍을 때는 데이터를 구조화해서 다루면 편하지만

 

1) 파일로 저장하거나

2) 네트워크를 통해 주고 받을 때는

 

쭈욱 늘어선 바이트들로 표현하는 것이 편하다.

 

- 구조화된 데이터를 serialize 해서 파일로 저장하거나, 네트워크를 통해 전송하고

- serialize 바이트들을 파일에서 읽거나, 네트워크를 통해 수신해서, 이를 deserialize 하여 구조화된 데이터로 만든다.

 

Serialize / Deserialize 방법

 

1) gobs: serialize / deserialize 주체가 golang 이라면 강추

2) ad-hoc way: 엄청 씸플한 데이터인 경우에는 단순한 약속을 정해서 처리해버리면 된다.

3) XML: 장점은 잉간이 읽기 편하다는 거고, 이미 많은 프로그래밍 언어가 지원한다는 .

- 하지만 용량과 작업량이 많고, 필드 하나를 찾아 돌아다니기도 복잡하다.

 

그렇다면 Protocol Buffes ?

 

1) .proto 파일을 작성한다. 스키마라 생각할 있겠다.

2) 그리고는 compiler 클래스를 생성한다.

- encoding, parsing 제공해주며

- getter, setter, read, write 제공해준다.

3) 무엇보다도 나중에 field 추가해줘도 이전 포맷으로 구현된 코드에서 (추가된 field 제외한) field 읽을 있다.

 

추가적으로 언급하고픈 protocol buffers 미덕은 (gobs 와는 다르게) 하나의 .proto 파일로

여러 언어들에 맞게 compile 가능하다는 것이다.

- golang 으로 serialize 하여 파일로 저장하거나, 네트워크로 보낸 것을, python 으로 읽거나, 받아서 사용할 있다.

 

 

실전 예제를 시작해보자.

 

전체 기능은 동일하게 유지하며, 나만의 방식으로 직접 작성해보겠음

구조는 유튜브의 튜토리얼을 참고하였음

- https://youtu.be/_jQ3i_fyqGA

- https://github.com/campoy/justforfunc/tree/master/30-protobuf

 

.proto 파일을 만들자

 


 

1) 프로젝트 폴더에 addbook 이라는 폴더를 만들고 addbook.proto 파일을 만들었다.

2) message AddressBook 은 여러 개의 Person 가지는 people field 가지고 있다.

3) message Person name, id, email, phones, last_updated 필드를 가진다.

 

- 필드에 붙은 숫자는 인코딩시에 해당 필드를 의미하게 된다. unique tag

- 1 to 15 숫자는 1바이트만 쓰니깐 최적화할때 고려할

- repeated field 라면 더욱 1 to 15 숫자를 사용해야 한다.

- 필드의 default 값은 0, "", false 이다.

 

enum 조금 들여다보자

 

링크: https://developers.google.com/protocol-buffers/docs/proto#enum

MOBILE, HOME, WORK 붙은 숫자는 int32 이다.

varint encoding 사용하기에 음수를 쓰면 불필요한 낭비가 발생한다.

allow_alias 옵션을 있다. STARTED = 1, RUNNING = 1 같이 여러 enum 같은 값을 가리키게 가능하다는 .

 

google/protobuf/timestamp.proto 뭘까?

 

링크: https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/timestamp.proto

일단 복잡한 차차 보면 되고, google.protobuf.Timestamp message 이며 2개의 field 가지고 있다는 것만 확인 완료

결국 이것도 message Person embedded message 셈이다.

 


 

.proto 파일을 컴파일하자

 

우선 아래 둘을 준비해둬야 한다.

 

1) 컴파일러 protoc

- 그냥 컴파일 된거 가져와서 압축을 풀어놓으면 된다.

- 링크: https://github.com/protocolbuffers/protobuf/releases/ 에서

1) protoc-3.8.0-win64.zip 다운받아 압축을 다음에

2) GOPATH bin 폴더에 다운받은 bin/protoc.exe 넣고,

3) GOPATH include 폴더를 복붙했다.

 

2) protoc-gen-go

- go get -d -u github.com/golang/protobuf/protoc-gen-go

- go install github.com/golang/protobuf/protoc-gen-go

 

그리고 컴파일 protoc --go_out . addbook.proto  해주면

. 으로 표시한 현재 폴더에 addbook.proto 컴파일한 addbook.pb.go 생성되었다.

 

- golang 안다면 생성된 파일을 한번 쭈욱 읽어보는 것도 좋겠다.

- 심화 링크https://developers.google.com/protocol-buffers/docs/reference/go-generated

 

생성된 .pb.go 에는 아래와 같은 녀석들이 써먹기 좋게 준비되어 있다.

 


 

CLI 프로그램을 만들자.

 

원래 튜토리얼에서는 개의 별도 프로그램을 만들었지만

여기서는 addbook 이라는 프로그램을 만들고, subcommand add list 추가하고 뒤에 파일명을 붙일 있도록 구현해본다.


구현 코드: https://github.com/nicewook/protobuf-addressbook

 

참고 코드1

- https://github.com/protocolbuffers/protobuf/blob/master/examples/add_person.go

- https://github.com/protocolbuffers/protobuf/blob/master/examples/list_people.go

참고 코드2

https://github.com/campoy/justforfunc/tree/master/30-protobuf

 

cmd 폴더 아래에 addbook 폴더를 만들고, main.go 파일을 생성함.

이후 go install ./cmd/addbook 명령을 주면, GOPATH bin 폴더에 addbook.exe 생성됨

 

기본 골격 만들기

 

개의 argument 받아서, subcommand 분기하고,

각각의 subcommand 대해 filename 파라미터로 넣어서 실행하도록 구현함

 

예를 들어

- addbook add ab1 이라고 치면, add 명령이 수행되며, 작업할 파일명은 ab1 된다.

- addbook list ab1 이라고 치면, list 명령이 수행되며 ab1 읽어서 뿌려준다.

 


 

add() 함수

 

1) promptAddPerson() 함수를 호출해서 주소록에 추가할 사람의 정보를 얻어낸다.

2) 기존의 address book 파일을 읽는데,

- 없으면 새로 생성해서 넣으면 되고,

- 있으면, 기존의 정보를 unmarshal 하여 메모리에 가지고 있는다.

3) 메모리상의 구조체 인스턴스에 새로운 사람의 정보를 추가한 다음 (append)

4) 다시 Marshaling 다음 ioutil.WriteFile 써준다.


 

실제로 콘솔창에서 정보를 받아 읽는 함수

 


 

list() 함수

 

별다른 것은 없음.

세세하고 이쁘게 출력할 필요까지는 못느껴서 그냥 출력만 하도록

 


 

반응형

'golang' 카테고리의 다른 글

Concurrent Logging - in Golang  (0) 2019.06.17
gRPC - Go Quick Start  (1) 2019.06.10
Protocol Buffers - overview  (1) 2019.06.06
justforfunc #30: The Basics of Protocol Buffers  (0) 2019.06.04
Staircase Problem  (0) 2019.05.30
반응형
잡학툰 뱃지
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함