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"
.
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()
.
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
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
" 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/
.