티스토리 뷰
개요
공식 페이지의 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
- 클린 애자일
- intellij
- 잡학툰
- JIRA
- 체호프
- 제이펍
- solid
- pool
- 인텔리제이
- postgres
- 독서
- 독서후기
- 노션
- 2023
- strange
- bun
- websocket
- Shortcut
- Gin
- API
- Bug
- agile
- golang
- OpenAI
- notion
- folklore
- go
- github
- ChatGPT
- 영화
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |