一個(gè)簡(jiǎn)單的用go語(yǔ)言開發(fā)gRPC程序例子。
安裝gRPC
gRPC的安裝需要3塊內(nèi)容
1. 安裝gRPC環(huán)境
這個(gè)環(huán)境包括gRPC編譯運(yùn)行時(shí)刻需要的庫(kù)。
$ go get google.golang.org/grpc
2. 安裝 Protocol Buffers v3
這個(gè)是protoc編譯器, 用來編譯.proto文件生成gRPC服務(wù)的go代碼。
直接從下面鏈接下載二進(jìn)制發(fā)布包即可:
https://github.com/google/protobuf/releases
選擇平臺(tái)對(duì)應(yīng)的zip包
protoc-<version>-<platform>.zip
解開之后在bin目錄下面會(huì)有一個(gè)protoc可執(zhí)行文件
3. 安裝protoc plugin for Go
這個(gè)工具在go編譯protoc文件的時(shí)候需要用到廓块。
$ go get -u github.com/golang/protobuf/protoc-gen-go
安裝完之后可執(zhí)行程序protoc-gen-go會(huì)存放在$GOROOT/bin或者$GOPATH/bin下面。
一個(gè)ToUpper的例子
這個(gè)例子是一個(gè)ToUpper程序,接收客戶端請(qǐng)求包含一個(gè)傳入字符串參數(shù)最欠,服務(wù)端返回大寫字符串示罗。
1. 定義protoc文件
$ cat proto/toupper.proto
syntax = "proto3";
package proto;
// The service definition.
service ToUpper{
// Sends a greeting
rpc Upper (UpperRequest) returns (UpperReply) {}
}
// The request message
message UpperRequest {
string name = 1;
}
// The response message
message UpperReply {
string message = 1;
}
定義了一個(gè)ToUpper服務(wù)惩猫,定義了兩個(gè)消息UpperRequest和UpperReply分別用來接收和回復(fù)消息。
2. 定義服務(wù)端代碼
$ cat main/server.go
package main
import (
"log"
"net"
"strings"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "toupper/proto"
"google.golang.org/grpc/reflection"
)
const (
port = ":50051"
)
type server struct{}
func (s *server) Upper(ctx context.Context, in *pb.UpperRequest) (*pb.UpperReply, error) {
log.Printf("Received: %s", in.Name)
return &pb.UpperReply{Message: strings.ToUpper(in.Name)}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterToUpperServer(s, &server{})
// Register reflection service on gRPC server.
reflection.Register(s)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
3. 客戶端代碼
$ cat main/client.go
package main
import (
"log"
"os"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "toupper/proto"
)
const (
address = "localhost:50051"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewToUpperClient(conn)
// Contact the server and print out its response.
name := "hello world"
if len(os.Args) > 1 {
name = os.Args[1]
}
r, err := c.Upper(context.Background(), &pb.UpperRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Response: %s", r.Message)
}
工程目錄結(jié)構(gòu)如下
toupper
├── main
│ ├── client.go
│ └── server.go
├── makefile
└── proto
└── toupper.proto
makefile文件
$ cat makefile
PB=proto/toupper.pb.go
all: client server
server: $(PB)
go build main/server.go
client: $(PB)
go build main/client.go
$(PB):
protoc -I proto toupper.proto --go_out=plugins=grpc:proto
clean:
rm -f $(PB) client server
編譯
$ make
protoc -I proto toupper.proto --go_out=plugins=grpc:proto
go build main/client.go
go build main/server.go
注意在編譯前需要把前面安裝的protoc和protoc-gen-go設(shè)置到PATH環(huán)境變量蚜点。
編譯完總共會(huì)生成3個(gè)文件:
- proto/toupper.pb.go
- 可執(zhí)行文件client, 和
- 可執(zhí)行文件server
運(yùn)行
在終端直接運(yùn)行server:
$ ./server
在另一個(gè)終端運(yùn)行client:
$ ./client
2017/10/27 15:54:10 Response: HELLO WORLD
$ ./client abcd
2017/10/27 15:54:14 Response: ABCD
這時(shí)我們可以看到在服務(wù)端的輸出:
2017/10/27 15:54:10 Received: hello world
2017/10/27 15:54:14 Received: abcd