Source From Here
PrefaceThis tutorial provides a basic Go programmer’s introduction to working with gRPC. By walking through this example you’ll learn how to:
It assumes that you have read the Introduction to gRPC and are familiar with protocol buffers. Note that the example in this tutorial uses the proto3 version of the protocol buffers language: you can find out more in the proto3 language guide and the Go generated code guide.
Why use gRPC?
Our example is a simple route mapping application that lets clients get information about features on their route, create a summary of their route, and exchange route information such as traffic updates with the server and other clients.
With gRPC we can define our service once in a .proto file and generate clients and servers in any of gRPC’s supported languages, which in turn can be run in environments ranging from servers inside a large data center to your own tablet — all the complexity of communication between different languages and environments is handled for you by gRPC. We also get all the advantages of working with protocol buffers, including efficient serialization, a simple IDL, and easy interface updating.
Example code and setup
The example code for our tutorial is in grpc/grpc-go/examples/route_guide. To download the example, clone the grpc-go repository by running the following command:
Then change your current directory to grpc-go/examples/route_guide
You also should have the relevant tools installed to generate the server and client interface code - if you don’t already, follow the setup instructions in the Go quick start guide.
Defining the service
Our first step (as you’ll know from the Introduction to gRPC) is to define the gRPC service and the method request and response types using protocol buffers. You can see the complete .proto file in examples/route_guide/routeguide/route_guide.proto.
To define a service, you specify a named service in your .proto file:
- service RouteGuide {
- ...
- }
A simple RPC where the client sends a request to the server using the stub and waits for a response to come back, just like a normal function call:
- // Obtains the feature at a given position.
- rpc GetFeature(Point) returns (Feature) {}
- // Obtains the Features available within the given Rectangle. Results are
- // streamed rather than returned at once (e.g. in a response message with a
- // repeated field), as the rectangle may cover a large area and contain a
- // huge number of features.
- rpc ListFeatures(Rectangle) returns (stream Feature) {}
- // Accepts a stream of Points on a route being traversed, returning a
- // RouteSummary when traversal is completed.
- rpc RecordRoute(stream Point) returns (RouteSummary) {}
- // Accepts a stream of RouteNotes sent while a route is being traversed,
- // while receiving other RouteNotes (e.g. from other users).
- rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
- // Points are represented as latitude-longitude pairs in the E7 representation
- // (degrees multiplied by 10**7 and rounded to the nearest integer).
- // Latitudes should be in the range +/- 90 degrees and longitude should be in
- // the range +/- 180 degrees (inclusive).
- message Point {
- int32 latitude = 1;
- int32 longitude = 2;
- }
For the materials here, it is from this lesson "Getting Started with Protocol Buffers in Go - Tutorial". So in order to know protocol buffer well, let's create one .proto as below:
- person/person.proto
- syntax = "proto3";
- package person;
- message SocialFollowers {
- int32 youtube = 1;
- int32 facebook = 2;
- };
- message Person {
- string name = 1;
- int32 age = 2;
- SocialFollowers socialFollowers = 3;
- }
Now let's check how to marsh/unmarsh protocol boffer:
- main.go
- package main
- import (
- "fmt"
- "log"
- person "proto_go_ex/person"
- proto "github.com/golang/protobuf/proto"
- )
- func main(){
- fmt.Println("Hello world!")
- john := &person.Person{
- Name: "John",
- Age: 24,
- SocialFollowers: &person.SocialFollowers {
- Youtube: 1,
- Facebook: 5,
- },
- }
- // Marshal data
- data, err := proto.Marshal(john)
- if err != nil {
- log.Fatalf("Marshalling error: %v\n", err)
- }
- fmt.Println(data)
- // Unmarshal data
- newPerson := &person.Person{}
- err = proto.Unmarshal(data, newPerson)
- if err != nil {
- log.Fatal("Unmarshalling error:", err)
- }
- fmt.Println(newPerson)
- }
Creating Protocol Buffer .proto
The lesson from now on is actually the materials of this video "Beginners Guide to gRPC in Go!". Before all, let's get the necessary packages:
Then to install protoc (reference):
Ok, now the first step to create gRPC service, we need to create our .proto file:
- chat/chat.proto
- syntax = "proto3";
- package chat;
- message Message {
- string body = 1;
- }
- service ChatService {
- rpc SayHello(Message) returns (Message) {}
- }
Now let's create another go file for convenience of future development:
- chat/chat.go
- package chat
- import (
- "log"
- "golang.org/x/net/context"
- )
- type Server struct {
- }
- func (s *Server) SayHello(ctx context.Context, message *Message) (*Message, error) {
- log.Printf("Receive message body from client: %s", message.Body)
- return &Message{Body: "Hello from the server"}, nil
- }
Generating client and server code
Now let's create code for server side:
- server.go
- package main
- import (
- "log"
- "net"
- "google.golang.org/grpc"
- pb "proto_go_ex/chat"
- )
- func main(){
- lis, err := net.Listen("tcp", ":9000")
- if err != nil {
- log.Fatalf("Fail to listen on port 9000: %v", err)
- }
- grpcServer := grpc.NewServer()
- s := pb.Server{}
- pb.RegisterChatServiceServer(grpcServer, &s)
- if err := grpcServer.Serve(lis); err != nil {
- log.Fatalf("Failed to serve gRPC server over port 9000: %v", err)
- }
- }
Then below is for the code of client:
- client.go
- package main
- import (
- "log"
- "golang.org/x/net/context"
- "google.golang.org/grpc"
- pb "proto_go_ex/chat"
- )
- func main(){
- var conn *grpc.ClientConn
- conn, err := grpc.Dial(":9000", grpc.WithInsecure())
- if err != nil {
- log.Fatalf("could not connect: %s", err)
- }
- defer conn.Close()
- c := pb.NewChatServiceClient(conn)
- message := pb.Message {
- Body: "Hello from the client!",
- }
- resp, err := c.SayHello(context.Background(), &message)
- if err != nil {
- log.Fatalf("Error when calling SayHello: %s", err)
- }
- log.Printf("Resp from Server: %s", resp.Body)
- }
From the server side, you can see below similar message too:
Supplement
* Getting Started with Protocol Buffers in Go - Tutorial
* Go Protobuf Tips
* Golang Development - Beginners Guide to gRPC in Go (1)!
* Golang gRPC 教學 - part 1
沒有留言:
張貼留言