Describes how to use GRPC and protobuf to quickly understand GRPC can refer to the first paragraph in this article: Grpc quick Start.
Interface development is the important position of software development, and is the cornerstone of modern software development. Embodied in both the front and back end of the separate Web front-end or mobile clients, and even based on different systems, programming language software systems, the API is acting as a bridge to the different end of the system linked together to form a solid business system.
web-based interfaces are usually RESTful APIs that combine JSON to pass information between the front and back ends, which is better suited for both front and rear separation and mobile clients to back-end communication, but for a micro-service architecture that hosts large-scale concurrency and high performance requirements, the RESTful based on JSON transmission is also suitable for A software architecture with high concurrency, strong scalability, and complex business logic. An interface based on whether the RESTful architecture can be simply a two-way stream (Bidrectional stream). GRPC and protocol buffer is to solve the above problems.
A brief introduction to GRPC and Protobuf can be seen in this article: Google Protocol buffer and GRPC profile Grpc & Protocol Buffer Practice
My local Gopath directory for/users/hww/work/go, a new catalog for our demo Project CD $GOPATH/src && mkdir rpc-protobuf definition Protocol Buffer The message types and services
Rpc-protobuf the new file directory in the project root directory customer. First, the Protocol bufffer file defines the service interface and the data structure of the PAYLAOD information, $GOPATH/scr/rpc-protobuf/customer/customer.proto:
syntax
= "Proto3";
Package customer; The Customer Sercie definition service Customer {//Get all Customers with filter-a server-to-client streaming R
Pc. RPC GetCustomers (customerfilter) returns (Stream customerrequest) {}//Create a new customer-a simple RPC RPC CreateCustomer (customerrequest) returns (Customerresponse) {}} message Customerrequest {int32 id = 1;
Unique ID number for a Customer.
String name = 2;
string email = 3;
string phone = 4;
Message Address {string street = 1;
String city = 2;
string state = 3;
string zip = 4;
BOOL isshippingaddress = 5;
} repeated address addresses = 5;
} message Customerresponse {int32 id = 1;
BOOL success = 2; } message customerfilter {string keyword = 1;}
In the. proto file, the first line of code is the version number, where we use the Proto3; the second line of code is the package name, the name of the go source package generated through the file and the consistent customer here
We define the message type and the service interface. Standard data types have int32, float, double, or string these common types. A message type is a collection of multiple fields, each of which is marked by an integer that is unique in the message; There are two RPC methods in the Customer service:
Service Customer {
//Get all Customers with filter-a server-to-client streaming RPC.
RPC GetCustomers (customerfilter) returns (Stream customerrequest) {}
//Create A new customer-a simple RPC
RPC C Reatecustomer (customerrequest) returns (Customerresponse) {}
}
Before explaining the Customer service, let's take a rough look at the three types of RPC methods in Grpc. Simple RPC
Applies to common typical request/response models. The client requests RPC's server via stub and waits for a response from the server. Server-side Streaming RPC
The client sends a request to the server and gets the stream returned by the server to read a series of service-side responses. The Stream keyword is in front of the response type. Example
RPC Lotsofreplies (hellorequest) returns (Stream helloresponse) {}
Client-side Streaming RPC
The request sent by the client payload has a series of messages that are sent to the server by streaming the request. The Stream keyword precedes the request type. Example
RPC Lotsofgreetings (Stream hellorequest) returns (Helloresponse) {}
Bidirectional streaming RPC
The Read-write stream is used to communicate between the server and the client. The Stream keyword precedes the request type and response type. Example
RPC Bidihello (Stream hellorequest) returns (Stream helloresponse) {}
After understanding the four types of RPC methods provided by GRPC, return to the Customer example. The Customer service provides two types of RPC methods, simple RPC (createcustomer) and Server-side streaming (getcustomers). CreateCustomer follows the standard request/response specification to create a new user; In GetCustomers method, the server returns a list of multiple consumer information through the stream. build server-side and client's go code based on proto file
After you have defined the proto file, then generate the programming language source code you need, which is the interface between the server side and the client business logic code. Client code invokes the RPC method through the message type and the service interface.
The protocol buffer compiler generates client and server-side code through the Grpc go plug-in. To run a command under the project root:
Protoc-i Customer/customer/customer.proto--go_out=plugins=grpc:customer
The Customer.pb.go file was generated in the customer directory. The source contains three broad categories of functionality: Read-write and serialization requests and response message types provide a client invocation method interface defined in the proto file to provide a service-side implementation interface defined in the proto file to create a new GRPC service
The following code fragment creates a new GRPC service side based on the service defined in the proto file.
Server/main.go Package main import ("Log" "NET" "Strings" "Golang.org/x/net/context" "Google.gol Ang.org/grpc "PB" Rpc-protobuf/customer ") const (port =": 50051 ")//server is used to implement customer.
CustomerServer. Type server struct {savedcustomers []*PB. Customerrequest}//CreateCustomer creates a new Customer func (S *server) CreateCustomer (CTX context. Context, in *PB. Customerrequest) (*PB. Customerresponse, error) {s.savedcustomers = append (S.savedcustomers, in) return &PB. Customerresponse{id:in. Id, success:true}, nil}//GetCustomers returns all customers by given filter func (S *server) GetCustomers (filter *pb. Customerfilter, stream PB. Customer_getcustomersserver) Error {for _, Customer: = Range S.savedcustomers {if filter. Keyword!= "" {if!strings. Contains (Customer. Name, filter. Keyword) {Continue}} If err: = stream. Send (customer); Err!= niL {return err}} return nil} func main () {lis, err: = Net. Listen ("TCP", port) if Err!= nil {log. Fatal ("Failed to listen:%v", err)}//create a new GRPC server s: = Grpc. NewServer () PB.
Registercustomerserver (S, &server{}) S.serve (LIS)}
In the server-side source code, the CustomerServer interface is defined in the Customer.pb.go; CreateCustomer and GetCustomers two methods are defined in Customer.pb.go file custome The Rclient interface.
CreateCustomer is a simple RPC-type RPC method, where it accepts two parameters, which are the context objct and client request information, and the return value is the Customerresponse object defined for the proto file; getc Ustomers is a server-side streaming type of RPC method that takes two parameters: Customerrequest object, and the object used as the server to respond to the stream to the client customer_getcustomers Server.
Look at the definition of the CustomerServer interface in Customer.pb.go:
Server API for Customer service
type CustomerServer interface {
//Get all Customers with Filter-a server-to- Client streaming RPC.
GetCustomers (*customerfilter, customer_getcustomersserver) error
//Create A new customer-a simple RPC
CreateCustomer (context. Context, *customerrequest) (*customerresponse, error)
}
By comparing the implementation of the service-side code to two methods, we can understand the principle of the transfer of parameters.
There is a line of code stream inside the GetCustomers method in the server-side code. Send (Customer) This send method is customer.pb.go to the Customer_getcustomersserver interface to define a good way to return the stream to the client
Finally, look at the main method in the server-side code.
First GRPC. NewServer function to create a new GRPC server;
Then call the Registercustomerserver (S *grpc in Customer.pb.go. Server, SRV customerserver) function to register the service: PB. Registercustomerserver (S, &server{});
Finally, the specified port number is monitored via the grpc golang API server.serve: S. Serve (LIS), a new servertransport and service Goroutine processing the listening port received requests. New GRPC Client
First look at the code generated by the CUSTOMER.PB.GO client calling method Interface section:
Client API for Customer service
type Customerclient interface {
//Get all Customers with Filter-a server-to- Client streaming RPC.
GetCustomers (CTX context. Context, in *customerfilter, opts ... grpc. Calloption) (customer_getcustomersclient, error)
//Create A new customer-a simple RPC
createcustomer (CTX Conte Xt. Context, in *customerrequest, opts ... grpc. Calloption) (*customerresponse, error)
}
type customerclient struct {
cc *grpc. Clientconn
}
func newcustomerclient (cc *grpc. Clientconn) customerclient {return
&customerclient{cc}
}
*grpc. Clientconn represents a client connected to the RPC server, and the Newcustomerclient function returns a Customerclient structure object. The Customerclient interface defines two methods that can be invoked by the client service, and in addition we can see a way to implement these two functions in customer.pb.go to the customerclient type of struct, so the client object can call GetCustomers and CreateCustomer methods:
Func (c *customerclient) GetCustomers (CTX context. Context, in *customerfilter, opts ... grpc. Calloption) (customer_getcustomersclient, error) {
...
}
...
Func (c *customerclient) CreateCustomer (CTX context. Context, in *customerrequest, opts ... grpc. Calloption) (*customerresponse, error) {
...
}
Then back to the implementation of the client source code:
Client/main.go Package Main import ("io" "Log" "Golang.org/x/net/context" "Google.golang.org/grpc" PB "Rpc-protobuf/customer") const (address = "localhost:50051")//CreateCustomer calls the RPC method Create Customer of CustomerServer func createcustomer (client PB. Customerclient, Customer *PB. Customerrequest) {resp, err: = client. CreateCustomer (context. Background (), customer) If Err!= nil {log. Fatalf ("Could not create Customer:%v", err)} if resp. Success {log. Printf ("A new Customer has been added with ID:%d", resp. ID)}//GetCustomers calls the RPC method GetCustomers of CustomerServer func getcustomers (client PB. Customerclient, filter *PB. Customerfilter) {//calling the streaming API stream, err: = client. GetCustomers (context. Background (), filter) If Err!= nil {log. Fatal ("Error on Get Customers:%v", err)} for {customer, err: = stream. RECV () If err = = Io. EThe {break} If Err!= nil {log. Fatal ("%v.getcustomers (_) = _,%v", Client, Err)} log. Printf ("Customer:%v", Customer)}} Func main () {//Set up a connection to the RPC server conn, err: = Grpc . Dial (address, grpc. Withinsecure ()) If Err!= nil {log. Fatal ("Did not connect:%v", err)} defer conn. Close ()//Creates a new Customerclient client: = PB. Newcustomerclient (conn) Customer: = &PB. customerrequest{id:101, Name: "Shiju Varghese", Email: "Shiju@xyz.com", Phone: "732- 757-2923 ", Addresses: []*PB. customerrequest_address{&PB. customerrequest_address{Street: ' 1 Mission Street ', City: "San Fr Ancisco ", State:" CA ", Zip:" 94105 ", Isshippinga Ddress:false,}, &PB. Customerrequest_address{Street: "The Greenfield", City: "Kochi",
State: "KL", Zip: "68356", Isshippingaddress:true, },},//Create a new customer CreateCustomer (client, customer) customer = &PB. customerrequest{id:102, Name: "Irene Rose", Email: "Irene@xyz.com", Phone: "732-757- 2924 ", Addresses: []*PB. customerrequest_address{&PB. customerrequest_address{Street: ' 1 Mission Street ', City: "San Fr Ancisco ", State:" CA ", Zip:" 94105 ", Isshippinga Ddress:true,},},//Create a new customer CreateCustomer (client, customer)//fil ter with a empty Keyword filter: = &PB. Customerfilter{keyword: ""} getcustomers (client, filter)}
The client needs to establish a GRPC channel (channel) to establish communication with the server and invoke the RPC method. Grpc. The dial function represents the new connection to the RPC server. The dial function declares the code in the library implemented by Grpc Golang as follows:
Func Dial (target string, opts ...) Dialoption) (*clientconn, error)
In addition to the connection address as the first parameter, you can also pass multiple optional parameters. These optional parameters represent authentication checksums, such as TLS or JWT. Here in the GRPC. Withinsecure indicates that the secure transport of client connections is disabled.
Before invoking the server-side RPC method, you first need to create a new client stub:
Creates a new customerclient
client: = PB. Newcustomerclient (conn)
In the example, two customer data was added by invoking the RPC CreateCustomer method: CreateCustomer (client, customer); Calling the RPC GetCustomers method to get all customers Data.
So far, we've simply implemented a set of GRPC client and server-side code. To run a command under the project root:
➜ Rpc-protobuf (Nohup go run server/main.go &) && go run client/main.go appending output to Nohup.out 2017/10/28 18:08:02 A new customer has been added with id:101 2017/10/28 18:08:02 A New customer has been added with id:102 2017/1 0/28 18:08:02 customer:id:101 Name: "Shiju Varghese" Email: "shiju@xyz.com" Phone: "732-757-2923" Addresses:<street: " 1 Mission Street ' city: San Francisco ' state: ' CA ' zip: ' 94105 ' > Addresses:<street: ' Greenfield ' city: ' Kochi ' state: "KL" Zip: "68356" Isshippingaddress:true > 2017/10/28 18:08:02 customer:id:102 Name: "Irene Rose" Email: "irene@xyz.com "Phone:" 732-757-2924 "Addresses:<street:" 1 Mission Street "City: San Francisco" state: "CA" Zip: "94105" Isshippingaddress:true > https://zhuanlan.zhihu.com/p/30624616