Serialisation: Protocol Buffers

Go

Compiling prototype files

The compile command is


      protoc --go_out=go/src/person personv3.proto
  
Note that the generated file is put in a subdirectory src. This allows the Go compiler to find it from the GOPATH environment variable.

Go is not officially supported by Protocol Buffers, so you will need to install the Go PB files. The instruction at Protocol Buffer Basics: Go says


      go install google.golang.org/protobuf/cmd/protoc-gen-go
  
This seems to be incorrect now, possibly the doco is ahead of the implementation. It currently needs to be

      go install github.com/golang/protobuf/cmd/protoc-gen-go
  
and in the applications using this, the import needs to be include "github.com/golang/protobuf/proto".

Structure of files

The generated file is src/person/personv3.pb.go. it contains structures person.Person, person.Person_Name and person.Person_Email.

The proto has functions Marshal() and Unmarshal().

Person client

The client creates the structures, calls proto.Marshal() to serialize the person, and then writes it to a server. It is PersonClient.go:


/*
*/

package main

import (
	"fmt"
        "github.com/golang/protobuf/proto"
        "os"
	"net"
        "person"
)

func main() {

	if len(os.Args) != 2 {
                fmt.Fprint(os.Stderr, "Usage: ", os.Args[0], " host:port\n")
                os.Exit(1)
        }
        service := os.Args[1]


        name := person.Person_Name{
                Family:   "newmarch",
                Personal: "jan"}

        email1 := person.Person_Email{
                Kind:    "home",
                Address: "jan@newmarch.name"}
        email2 := person.Person_Email{
                Kind:    "work",
                Address: "j.newmarch@boxhill.edu.au"}

        emails := []*person.Person_Email{&email1, &email2}
        p := person.Person{
                Name:  &name,
                Email: emails,
        }
        fmt.Println(p)

        data, err := proto.Marshal(&p)
        checkError(err)

	conn, err := net.Dial("tcp", service)
        checkError(err)
        fmt.Println("Connected")

	_, err = conn.Write(data)
	checkError(err)


}

func checkError(err error) {
        if err != nil {
                fmt.Println("Fatal error ", err.Error())
                os.Exit(1)
        }
}

To run it, you need to set GOPATH to find all the relevant files. In my system it is


      GOPATH=/home/.../go:/usr/lib/go-1.10/
      go run PersonClient.go localhost:2001
  

Person server

The server listens, reads binary data and calls proto.Unmarshal(). It just has to be careful ot to pass in the entire byte array, just the slice read. It is PersonServer.go:


/* SimpleEchoServer
 */
package main

import (
	"fmt"
	"net"
	"os"
	"github.com/golang/protobuf/proto"
	"person"
)

func main() {

	service := ":2001"
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	checkError(err)

	listener, err := net.ListenTCP("tcp", tcpAddr)
	checkError(err)

	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		fmt.Println("Connected")
		// run as a coroutine
		go handleClient(conn)
	}
}

func handleClient(conn net.Conn) {
	// close connection on exit
        defer conn.Close()

	var data []byte
	data = make([]byte, 128, 128)

	nread, err := conn.Read(data)
	if err != nil {
		fmt.Println("Disconnecting")
		return
	}
	
	p := &person.Person{}
	err = proto.Unmarshal(data[0:nread], p)
	if err != nil {
		fmt.Println("Error unmarshalling %s", err.Error())
		return
	}
	fmt.Println("Received: ", p)
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
		os.Exit(1)
	}
}

To run it, you need to set GOPATH to find all the relevant files. In my system it is

      GOPATH=/home/.../go:/usr/lib/go-1.10/
      go run PersonServer.go
  


Copyright © Jan Newmarch, jan@newmarch.name
Creative Commons License
" Network Programming using Java, Go, Python, Rust, JavaScript and Julia" by Jan Newmarch is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License .
Based on a work at https://jan.newmarch.name/NetworkProgramming/ .

If you like this book, please contribute using PayPal