??gRPC是Google的RPC框架,开源、高性能、跨语言,基于HTTP/2通讯协议和Protocol Buffer 3数据序列化协议。 过程如下图所示: ??调用的双方可以使用完全不同的两种语言来实现,分别实现client端和server端,按照约定的protobuf协议进行交互。client端会保存与server端的长连接对象或叫存根,通过这个存根可以直接调用服务端的方法。而服务端则实现了proto中指定的服务接口。
proto的安装
要编译proto文件生成go代码需要两个工具
- protoc :用于编译(其他语言只需要protoc足以)
- protoc-gen-go : 用于生成go语言的文件(go语言专用插件)
1、protoc-gen-go下载:
go get github.com/golang/protobuf/protoc-gen-go@H_502_30@
会直接生成protoc-gen-go 二进制文件到GOPATH的bin目录。 2、protoc下载:https://github.com/google/protobuf/releases 找到对应平台win/linux/mac的下载包,复制二进制文件protoc到GOPATH的bin目录。
定义proto文件
Syntax = "proto3";
package protos;
message User{
int32 id = 1;
string name = 2;
}
message UserReq{
int32 id = 1;
}
service IUserService {
rpc Get (UserReq) returns (User);
rpc GetList (UserReq) returns (stream User);
rpc WaitGet(stream UserReq) returns (User);
rpc LoopGet(stream UserReq) returns (stream User);
}@H_502_30@
编译proto生成go文件
这里要使用grpc插件选项:
protoc --go_out=plugins=grpc:. 路径/*.proto@H_502_30@
会在同目录下生成.pb.go文件。如果不识别protoc,则说明GOPATH的bin目录不在环境变量中,需要设置。
安装grpc包
go get google.golang.org/grpc@H_502_30@
实现grpc的server端
1、接口实现,即对外提供的服务API。
package service
import (
"fmt"
"io"
"log"
"protos"
"strconv"
"golang.org/x/net/context"
)
func NewUserService() *UserService {
return &UserService{}
}
type UserService struct {
}
func (this *UserService) Get(ctx context.Context,req *protos.UserReq) (*protos.User,error) {
return &protos.User{Id: 1,Name: "shuai"},nil
}
func (this *UserService) GetList(req *protos.UserReq,stream protos.IUserService_GetListServer) error {
fmt.Println(*req)
for i := 0; i < 5; i++ {
stream.Send(&protos.User{Id: int32(i),Name: "我是" + strconv.Itoa(i)})
}
return nil
}
func (this *UserService) WaitGet(reqStream protos.IUserService_WaitGetServer) error {
for {
userReq,err := reqStream.Recv()
if err != io.EOF {
fmt.Println("流请求~",*userReq)
} else {
return reqStream.SendAndClose(&protos.User{Id: 100,Name: "shuai"})
}
}
}
func (this *UserService) LoopGet(reqStream protos.IUserService_LoopGetServer) error {
for {
userReq,err := reqStream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if err = reqStream.Send(&protos.User{Id: userReq.Id,Name: "shuai"}); err != nil {
return err
}
}
}@H_502_30@
2、启动服务
package main
import (
"flag"
"fmt"
"net"
"proj/service"
"protos"
"google.golang.org/grpc"
)
var (
addr = flag.String("host","127.0.0.1:9000","")
)
func main() {
lis,err := net.Listen("tcp",*addr)
if err != nil {
fmt.Println("listen error!")
return
}
grpcServer := grpc.NewServer()
protos.RegisterIUserServiceServer(grpcServer,service.NewUserService())
grpcServer.Serve(lis)
}@H_502_30@
go run main.go @H_502_30@
实现grpc的client端
package main
import (
"flag"
"fmt"
"io"
"log"
"protos"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
var (
addr = flag.String("host","")
userCli protos.IUserServiceClient
)
func main() {
conn,err := grpc.Dial(*addr)
if err != nil {
log.Fatal("@R_502_159@ to connect : ",err)
}
userCli = protos.NewIUserServiceClient(conn)
TestGet()
TestGetList()
TestWaitGet()
}
func TestGet() {
user,err := userCli.Get(context.Background(),&protos.UserReq{Id: 1})
if err != nil {
fmt.Printf("Get connect @R_502_159@ :%v",err)
return
}
log.Println("Get响应数据:",*user)
}
func TestGetList() {
recvStream,err := userCli.GetList(context.Background(),&protos.UserReq{Id: 1})
if err != nil {
fmt.Printf("GetList connect @R_502_159@ :%v",err)
return
}
for {
user,err := recvStream.Recv()
if err == io.EOF {
break
}
log.Println("GetList获取的一条响应数据:",*user)
}
}
func TestWaitGet() {
sendStream,err := userCli.WaitGet(context.Background())
if err != nil {
fmt.Printf("WaitGet connect @R_502_159@ :%v",err)
return
}
for i := 0; i < 5; i++ {
if err = sendStream.Send(&protos.UserReq{Id: int32(i)}); err != nil {
fmt.Printf("WaitGet send @R_502_159@ :%v",err)
return
}
}
user,err := sendStream.CloseAndRecv()
if err != nil {
fmt.Printf("WaitGet recv @R_502_159@ :%v",err)
return
}
log.Println("WaitGet响应数据:",*user)
}@H_502_30@
启动client端:
go run main.go@H_502_30@ (编辑:北几岛)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|