16
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

protocol buffers をGolangで使う

Posted at

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"
        }
      ]
    }
  ]
}
16
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?