内容简介:gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
安装 protobuf & protoc
grpc
使用 protobuf
作为 IDL
,且要求 protobuf
3.0 以上,这里我们直接选用当前最新版本 3.8, git下载地址
。选择操作系统对应的版本下载,这里我们直接使用已经编译好的 protoc
可执行文件(或者下载安装包编译安装)。
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.8.0-rc1/protoc-3.8.0-rc-1-linux-x86_64.zip tar -zxvf protoc-3.8.0-rc-1-linux-x86_64.zip mv protoc-3.8.0-rc-1-linux-x86_64 /usr/local/protoc ln -s /usr/local/protoc/bin/protoc /usr/local/bin/protoc #查看 protoc protoc --version
安装 grpc-go
grpc-go
包含了 golang
的 grpc
库,我们还要安装 golang
的 protoc
编译插件 protoc-gen-go
( protoc
自带的支持很多语言,唯独没有 go
的)。
git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text go get -u github.com/golang/protobuf/{proto,protoc-gen-go} git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto cd $GOPATH/src/ go install google.golang.org/grpc
protoc-gen-go
是 protobuf
编译插件系列中的 Go
版本,原生的 protoc
并不包含 Go
版本的插件。
# 运行 protoc -h 命令可以发现内置的只支持以下语言 protoc -h ... --cpp_out=OUT_DIR Generate C++ header and source. --csharp_out=OUT_DIR Generate C# source file. --java_out=OUT_DIR Generate Java source file. --js_out=OUT_DIR Generate JavaScript source. --objc_out=OUT_DIR Generate Objective C header and source. --php_out=OUT_DIR Generate PHP source file. --python_out=OUT_DIR Generate Python source file. --ruby_out=OUT_DIR Generate Ruby source file. ...
protoc-gen-go
是 Go
写的,只需要运行 go get -u github.com/golang/protobuf/protoc-gen-go
,便可以在 $GOPATH/bin
目录下发现这个工具。
grpc
借口的类型分为一下四种: A
为接受参数, B
为返回参数
- rpc GetFeature(Point) returns (Feature) {} 普通调用:A-B
- rpc ListFeatures(Rectangle) returns (stream Feature) {} 单向流:A - B(流)
- rpc RecordRoute(stream Point) returns (RouteSummary) {} 单向流:A(流) - B
- rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} 双向流:A(流) - B(流)
我们只演示最基础的普通调用,开始撸。
Go实例
下面我们将创建一个提供 CURD
操作的 User
服务。
#创建一个 grpc 服务库 mkdir $GOPATH/src/grpc/user -p && cd $GOPATH/src/grpc
定义服务接口
使用 proto3 IDL
编写如下的用户服务。
vi user.proto
syntax = "proto3"; // user 包 package user; // User 服务及服务接口的定义 service User { rpc UserIndex(UserIndexRequest) returns (UserIndexResponse) {} rpc UserView(UserViewRequest) returns (UserViewResponse) {} rpc UserPost(UserPostRequest) returns (UserPostResponse) {} rpc UserDelete(UserDeleteRequest) returns (UserDeleteResponse) {} } // 用户实体模型 message UserEntity { string name = 1; int32 age = 2; } // User 服务的各个接口的请求/响应结构 message UserIndexRequest { int32 page = 1; int32 page_size = 2; } message UserIndexResponse { int32 err = 1; string msg = 2; // 返回一个 UserEntity 对象的列表数据 repeated UserEntity data = 3; } message UserViewRequest { int32 uid = 1; } message UserViewResponse { int32 err = 1; string msg = 2; // 返回一个 UserEntity 对象 UserEntity data = 3; } message UserPostRequest { string name = 1; string password = 2; int32 age = 3; } message UserPostResponse { int32 err = 1; string msg = 2; } message UserDeleteRequest { int32 uid = 1; } message UserDeleteResponse { int32 err = 1; string msg = 2; }
生成接口库
# 将 User 服务的所属包 user package 存放在 $GOPATH/src/grpc/user 下 protoc -I. --go_out=plugins=grpc:./user user.proto
编写服务端
vi server.go
package main import ( "context" "log" "net" "google.golang.org/grpc" "google.golang.org/grpc/reflection" user "grpc/user" ) const ( port = ":50051" ) type UserService struct { // 实现 User 服务的业务对象 } // UserService 实现了 User 服务接口中声明的所有方法 func (userService *UserService) UserIndex(ctx context.Context, in *user.UserIndexRequest) (*user.UserIndexResponse, error) { log.Printf("receive user index request: page %d page_size %d", in.Page, in.PageSize) return &user.UserIndexResponse{ Err: 0, Msg: "success", Data: []*user.UserEntity{ {Name: "big_cat", Age: 28}, {Name: "sqrt_cat", Age: 29}, }, }, nil } func (userService *UserService) UserView(ctx context.Context, in *user.UserViewRequest) (*user.UserViewResponse, error) { log.Printf("receive user view request: uid %d", in.Uid) return &user.UserViewResponse{ Err: 0, Msg: "success", Data: &user.UserEntity{Name: "james", Age: 28}, }, nil } func (userService *UserService) UserPost(ctx context.Context, in *user.UserPostRequest) (*user.UserPostResponse, error) { log.Printf("receive user post request: name %s password %s age %d", in.Name, in.Password, in.Age) return &user.UserPostResponse{ Err: 0, Msg: "success", }, nil } func (userService *UserService) UserDelete(ctx context.Context, in *user.UserDeleteRequest) (*user.UserDeleteResponse, error) { log.Printf("receive user delete request: uid %d", in.Uid) return &user.UserDeleteResponse{ Err: 0, Msg: "success", }, nil } func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } // 创建 RPC 服务容器 grpcServer := grpc.NewServer() // 为 User 服务注册业务实现 将 User 服务绑定到 RPC 服务容器上 user.RegisterUserServer(grpcServer, &UserService{}) // 注册反射服务 这个服务是CLI使用的 跟服务本身没有关系 reflection.Register(grpcServer) if err := grpcServer.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }
编写客户端
vi client.go
package main import ( "context" "fmt" "log" "time" "google.golang.org/grpc" user "grpc/user" ) const ( address = "localhost:50051" defaultName = "world" ) func main() { //建立链接 conn, err := grpc.Dial(address, grpc.WithInsecure()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() userClient := user.NewUserClient(conn) // 设定请求超时时间 3s ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) defer cancel() // UserIndex 请求 userIndexReponse, err := userClient.UserIndex(ctx, &user.UserIndexRequest{Page: 1, PageSize: 12}) if err != nil { log.Printf("user index could not greet: %v", err) } if 0 == userIndexReponse.Err { log.Printf("user index success: %s", userIndexReponse.Msg) // 包含 UserEntity 的数组列表 userEntityList := userIndexReponse.Data for _, row := range userEntityList { fmt.Println(row.Name, row.Age) } } else { log.Printf("user index error: %d", userIndexReponse.Err) } // UserView 请求 userViewResponse, err := userClient.UserView(ctx, &user.UserViewRequest{Uid: 1}) if err != nil { log.Printf("user view could not greet: %v", err) } if 0 == userViewResponse.Err { log.Printf("user view success: %s", userViewResponse.Msg) userEntity := userViewResponse.Data fmt.Println(userEntity.Name, userEntity.Age) } else { log.Printf("user view error: %d", userViewResponse.Err) } // UserPost 请求 userPostReponse, err := userClient.UserPost(ctx, &user.UserPostRequest{Name: "big_cat", Password: "123456", Age: 29}) if err != nil { log.Printf("user post could not greet: %v", err) } if 0 == userPostReponse.Err { log.Printf("user post success: %s", userPostReponse.Msg) } else { log.Printf("user post error: %d", userPostReponse.Err) } // UserDelete 请求 userDeleteReponse, err := userClient.UserDelete(ctx, &user.UserDeleteRequest{Uid: 1}) if err != nil { log.Printf("user delete could not greet: %v", err) } if 0 == userDeleteReponse.Err { log.Printf("user delete success: %s", userDeleteReponse.Msg) } else { log.Printf("user delete error: %d", userDeleteReponse.Err) } }
启动服务/请求服务
go run server.go # 新建一个窗口 go run client.go
运行结果
#server [root@localhost rpc]# go run server.go 2019/05/16 00:28:01 receive user index request: page 1 page_size 12 2019/05/16 00:28:01 receive user view request: uid 1 2019/05/16 00:28:01 receive user post request: name big_cat password 123456 age 29 2019/05/16 00:28:01 receive user delete request: uid 1 #client [root@localhost rpc]# go run client.go 2019/05/16 00:28:01 user index success: success big_cat 28 sqrt_cat 29 2019/05/16 00:28:01 user view success: success james 28 2019/05/16 00:28:01 user post success: success 2019/05/16 00:28:01 user delete success: success
grpc
面向服务接口编程大致就是这样啦,你可以更好的组织业务库,我这里全放在 package main
里了,后面的工作就是把数据库拉进来了。
第二篇我们将以 PHP
作为客户端请求 Go
服务端。
以上所述就是小编给大家介绍的《grpc - 使用 golang 带你从头撸一套 RPC 服务(一)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 使用 Swift 从头构建 LISP 解释器
- .net – 如何使用HtmlAgility包从头开始创建html文档
- grpc - 使用 golang 带你从头撸一套 RPC 服务(二)
- 不使用先验知识与复杂训练策略,从头训练二值神经网络!
- GraphQL:从头开始
- 从头手写一个Promise
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
现代密码学理论与实践
毛文波 / 电子工业出版社 / 2004-1 / 49.00元
现代密码学理论与实践,ISBN:9787505399259,作者:(英)Wenbo Mao著;王继林,伍前红等译;王继林译一起来看看 《现代密码学理论与实践》 这本书的介绍吧!