gRPC with golang
intro
- sample three timer gRPC service in a golang.
- when input 1, returns 3
- works in a stream
preview
1
2
3
4
5
6
7
8
9
10
11
./client
2020/02/10 12:11:11 Got message : (0 attempt: _three_timed 0)
2020/02/10 12:11:12 Got message : (1 attempt: _three_timed 3)
2020/02/10 12:11:12 Got message : (2 attempt: _three_timed 6)
2020/02/10 12:11:13 Got message : (3 attempt: _three_timed 9)
2020/02/10 12:11:13 Got message : (4 attempt: _three_timed 12)
2020/02/10 12:11:14 Got message : (5 attempt: _three_timed 15)
2020/02/10 12:11:14 Got message : (6 attempt: _three_timed 18)
2020/02/10 12:11:15 Got message : (7 attempt: _three_timed 21)
2020/02/10 12:11:15 Got message : (8 attempt: _three_timed 24)
2020/02/10 12:11:16 Got message : (9 attempt: _three_timed 27)
howto
- install protocol buffer (using homebrew on OSX)
1
brew install protobuf
- install protoc-gen-go to use
--go_out
and move it(make symbolic link) to the$PATH
1
2
3
go get -u github.com/golang/protobuf/protoc-gen-go
cd /usr/local/bin
ln -s $GOPATH/bin/protoc-gen-go
- generate stub of golang using protoc
1
2
cd grpc-tester
protoc -I proto/v1/ --go_out=plugins=grpc:proto/v1 proto/v1/threetimer.proto
sample codes
- protobuf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
syntax = "proto3";
package threetimer;
// gRPC service definition
service ThreeTimesService {
// input as a stream, output also as a stream
rpc ThreeTimes(stream Data) returns (stream Data) {}
}
// protobuf message definition
message Data {
string name = 1;
int32 value = 2;
}
- server side
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
31
32
33
34
35
36
37
38
39
40
type threeTimerServer struct {
pb.UnimplementedThreeTimesServiceServer
}
func main() {
lis, err := net.Listen("tcp", "localhost:5000")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
server := grpc.NewServer()
srv := new(threeTimerServer)
pb.RegisterThreeTimesServiceServer(server, srv)
err = server.Serve(lis)
if err != nil {
fmt.Println(err)
}
}
func (*threeTimerServer) ThreeTimes(stream pb.ThreeTimesService_ThreeTimesServer) error {
for {
in, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
out := &pb.Data{
Name: in.Name + "_three_timed",
Value: in.Value * 3,
}
if err := stream.Send(out); err != nil {
return err
}
}
}
- client side
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
31
32
33
34
35
36
37
38
39
40
41
42
43
conn, err := grpc.Dial("localhost:5000", grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewThreeTimesServiceClient(conn)
// Contact the server and print out its response.
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
stream, err := c.ThreeTimes(ctx)
if err != nil {
log.Fatal(err)
}
waitChan := make(chan struct{})
go func() {
for {
in, err := stream.Recv()
if err == io.EOF {
// read done.
close(waitChan)
return
}
if err != nil {
log.Fatalf("Failed to receive : %v", err)
}
log.Printf("Got message : (%v %v)", in.Name, in.Value)
}
}()
for i := 0; i < 10; i++ {
time.Sleep(500 * time.Millisecond)
if err := stream.Send(&pb.Data{
Name: fmt.Sprint(i) + " attempt: ",
Value: int32(i),
}); err != nil {
log.Fatalf("Failed to send : %v", err)
}
}
stream.CloseSend()
<-waitChan
references
- https://github.com/fransoaardi/grpc-tester
- https://grpc.io/
This post is licensed under CC BY 4.0 by the author.
Comments powered by Disqus.