protocol buffersって名前は聞くけど、今まで使ったことなかったので、とりあえず触ってみた。
「protocol buffersでシリアライズしたデータをTCPで送信し、受信側はそれをjsonに変換して標準出力にアウトプットするプログラム」を作ってみることにする。
1. データ定義
とりあえず動かしてみるのが目的で、データは何でも良いので、tutorialからコピペしてきたものを使う。
addressbook.proto
syntax = "proto3";
package pb;
import "google/protobuf/timestamp.proto";
message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
google.protobuf.Timestamp last_updated = 5;
}
// Our address book file is just one of these.
message AddressBook {
repeated Person people = 1;
}
2. コンパイル
protoc --go_out=./ ./addressbook.proto
成功するとgoのソースが作られる。
3. tcpclientを書く
pbというのが、生成されたgoファイルのあるパッケージ
import文は省略
package main
func main() {
p := pb.Person{
Id: 1234,
Name: "John Doe",
Email: "jdoe@example.com",
Phones: []*pb.Person_PhoneNumber{
{Number: "555-4321", Type: pb.Person_HOME},
},
}
book := &pb.AddressBook{}
book.People = append(book.People, &p)
out, err := proto.Marshal(book)
if err != nil {
log.Fatal("Failed to encode\n")
}
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
panic(err)
}
conn.Write(out)
}
4. tcpserverを書く
pbというのが、生成されたgoファイルのあるパッケージ
import文は省略
jsonとprotocol buffersの変換はjsonpbというパッケージが提供されている。
https://godoc.org/github.com/golang/protobuf/jsonpb
package main
func main() {
ln, err := net.Listen("tcp", ":8080")
if err != nil {
panic(err)
}
for {
conn, err := ln.Accept()
if err != nil {
panic(err)
}
go func() {
var buf bytes.Buffer
io.Copy(&buf, conn)
book := &pb.AddressBook{}
if err := proto.Unmarshal(buf.Bytes(), book); err != nil {
log.Fatalln("Failed to parse address book:", err)
}
addressBookMarshaler := jsonpb.Marshaler{Indent: " "}
addressBookMarshaler.Marshal(os.Stdout, book)
}()
}
}
5. 実行
サーバ側の標準出力で下記が出力されることを確認。
{
"people": [
{
"name": "John Doe",
"id": 1234,
"email": "jdoe@example.com",
"phones": [
{
"number": "555-4321",
"type": "HOME"
}
]
}
]
}