大佬教程收集整理的这篇文章主要介绍了gRPC学习之四:实战四类服务方法,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
https://github.com/zq2599/blog_demos
内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;
名称 | 链接 | 备注 |
---|---|---|
项目主页 | https://github.com/zq2599/blog_demos | 该项目在GitHub上的主页 |
git仓库地址(@R_696_10107@s) | https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,@R_696_10107@s协议 |
git仓库地址(ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh协议 |
[golang@centos7 src]$ tree grpcstream/
grpcstream/
├── client
│ └── client.go
├── grpcstream.pb.go
├── grpcstream.proto
└── server
└── server.go
// 协议类型
syntax = "proto3";
// 包名
package grpcstream;
// 服务端请求的数据结构
message Singlerequest {
int32 id = 1;
}
// 服务端响应的数据结构
message SingleResponse {
int32 id = 1;
String name = 2;
}
// 定义的服务名
service IGrpcStremservice {
// 单项RPC :单个请求,单个响应
rpc SingleReqSingleResp (Singlerequest) returns (SingleResponsE);
// 服务端流式 :单个请求,集合响应
rpc SingleReqMultiResp (Singlerequest) returns (stream SingleResponsE);
// 客户端流式 :集合请求,单个响应
rpc MultiReqSingleResp (stream Singlerequest) returns (SingleResponsE);
// 双向流式 :集合请求,集合响应
rpc MultiReqMultiResp (stream Singlerequest) returns (stream SingleResponsE);
}
protoc --go_out=plugins=grpc:. grpcstream.proto
type IGrpcStremserviceServer interface {
// 单项流式 :单个请求,单个响应
SingleReqSingleResp(context.Context, *Singlerequest) (*SingleResponse, error)
// 服务端流式 :单个请求,集合响应
SingleReqMultiResp(*Singlerequest, IGrpcStremservice_SingleReqMultiRespServer) error
// 客户端流式 :集合请求,单个响应
MultiReqSingleResp(IGrpcStremservice_MultiReqSingleRespServer) error
// 双向流式 :集合请求,集合响应
MultiReqMultiResp(IGrpcStremservice_MultiReqMultiRespServer) error
}
type IGrpcStremserviceClient interface {
// 单项流式 :单个请求,单个响应
SingleReqSingleResp(ctx context.Context, in *Singlerequest, opts ...grpc.CallOption) (*SingleResponse, error)
// 服务端流式 :单个请求,集合响应
SingleReqMultiResp(ctx context.Context, in *Singlerequest, opts ...grpc.CallOption) (IGrpcStremservice_SingleReqMultiRespClient, error)
// 客户端流式 :集合请求,单个响应
MultiReqSingleResp(ctx context.Context, opts ...grpc.CallOption) (IGrpcStremservice_MultiReqSingleRespClient, error)
// 双向流式 :集合请求,集合响应
MultiReqMultiResp(ctx context.Context, opts ...grpc.CallOption) (IGrpcStremservice_MultiReqMultiRespClient, error)
}
package main
import (
"context"
"google.golang.org/grpc"
pb "grpcstream"
"io"
"log"
"net"
"strconv"
)
// 常量:监听端口
const (
port = ":50051"
)
// 定义结构体,在调用注册api的时候作为入参,
// 该结构体会带上proto中定义的方法,里面是业务代码
// 这样远程调用时就执行了业务代码了
type server struct {
// pb.go中自动生成的,是个空结构体
pb.UnimplementedIGrpcStremserviceServer
}
// 单项流式 :单个请求,单个响应
func (s *server) SingleReqSingleResp(ctx context.Context, req *pb.Singlerequest) (*pb.SingleResponse, error) {
id := req.GetId()
// 打印请求参数
log.Println("1. 收到请求:", id)
// 实例化结构体SingleResponse,作为返回值
return &pb.SingleResponse{Id: id, Name: "1. name-" + strconv.Itoa(int(id))}, nil
}
// 服务端流式 :单个请求,集合响应
func (s *server) SingleReqMultiResp(req *pb.Singlerequest, stream pb.IGrpcStremservice_SingleReqMultiRespServer) error {
// 取得请求参数
id := req.GetId()
// 打印请求参数
log.Println("2. 收到请求:", id)
// 返回多条记录
for i := 0; i < 10; i++ {
stream.Send(&pb.SingleResponse{Id: int32(i), Name: "2. name-" + strconv.Itoa(i)})
}
return nil
}
// 客户端流式 :集合请求,单个响应
func (s *server) MultiReqSingleResp(reqStream pb.IGrpcStremservice_MultiReqSingleRespServer) error {
var addVal int32 = 0
// 在for循环中接收流式请求
for {
// 一次接受一条记录
singlerequest, err := reqStream.Recv()
// 不等于io.EOF表示这是条有效记录
if err == io.EOF {
log.Println("3. 客户端发送完毕")
break
} else if err != nil {
log.Fatalln("3. 接收时发生异常", err)
break
} else {
log.Println("3. 收到请求:", singlerequest.GetId())
// 收完之后,执行SendAndClose返回数据并结束本次调用
addVal += singlerequest.GetId()
}
}
return reqStream.SendAndClose(&pb.SingleResponse{Id: addVal, Name: "3. name-" + strconv.Itoa(int(addVal))})
}
// 双向流式 :集合请求,集合响应
func (s *server) MultiReqMultiResp(reqStream pb.IGrpcStremservice_MultiReqMultiRespServer) error {
// 简单处理,对于收到的每一条记录都返回一个响应
for {
singlerequest, err := reqStream.Recv()
// 不等于io.EOS表示这是条有效记录
if err == io.EOF {
log.Println("4. 接收完毕")
return nil
} else if err != nil {
log.Fatalln("4. 接收时发生异常", err)
return err
} else {
log.Println("4. 接收到数据", singlerequest.GetId())
id := singlerequest.GetId()
if sendErr := reqStream.Send(&pb.SingleResponse{Id: id, Name: "4. name-" + strconv.Itoa(int(id))}); sendErr != nil {
log.Println("4. 返回数据异常数据", sendErr)
return sendErr
}
}
}
}
func main() {
// 要监听的协议和端口
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// 实例化gRPC server结构体
s := grpc.NewServer()
// 服务注册
pb.RegisterIGrpcStremserviceServer(s, &server{})
log.Println("开始监听,等待远程调用...")
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
[golang@centos7 server]$ go run server.go
2020/12/13 21:29:19 开始监听,等待远程调用...
package main
import (
"context"
"google.golang.org/grpc"
"io"
"log"
"time"
pb "grpcstream"
)
const (
address = "localhost:50051"
defaultId = "666"
)
func main() {
// 远程连接服务端
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
// main方法执行完毕后关闭远程连接
defer conn.Close()
// 实例化数据结构
client := pb.NewIGrpcStremserviceClient(conn)
// 超时设置
ctx, cancel := context.WithTimeout(context.BACkground(), time.Second)
defer cancel()
log.Println("测试单一请求应答,一对一")
singleReqSingleResp(ctx, client)
log.Println("测试服务端流式应答,一对多")
singleReqMultiResp(ctx, client)
log.Println("测试客户端流式请求,多对一")
multiReqSingleResp(ctx, client)
log.Println("测试双向流式请求应答,多对多")
multiReqMultiResp(ctx, client)
log.Println("测试完成")
}
func singleReqSingleResp(ctx context.Context, client pb.IGrpcStremserviceClient) error {
// 远程调用
r, err := client.SingleReqSingleResp(ctx, &pb.Singlerequest{Id: 101})
if err != nil {
log.Fatalf("1. 远程调用异常 : %v", err)
return err
}
// 将服务端的返回信息打印出来
log.Printf("response, id : %d, name : %s", r.GetId(), r.GetName())
return nil
}
func singleReqMultiResp(ctx context.Context, client pb.IGrpcStremserviceClient) error {
// 远程调用
recvStream, err := client.SingleReqMultiResp(ctx, &pb.Singlerequest{Id: 201})
if err != nil {
log.Fatalf("2. 远程调用异常 : %v", err)
return err
}
for {
singleResponse, err := recvStream.Recv()
if err == io.EOF {
log.Printf("2. 获取数据完毕")
break
}
log.Printf("2. 收到服务端响应, id : %d, name : %s", singleResponse.GetId(), singleResponse.GetName())
}
return nil
}
func multiReqSingleResp(ctx context.Context, client pb.IGrpcStremserviceClient) error {
// 远程调用
sendStream, err := client.MultiReqSingleResp(ctX)
if err != nil {
log.Fatalf("3. 远程调用异常 : %v", err)
return err
}
// 发送多条记录到服务端
for i:=0; i<10; i++ {
if err = sendStream.Send(&pb.Singlerequest{Id: int32(300+i)}); err!=nil {
log.Fatalf("3. 通过流发送数据异常 : %v", err)
return err
}
}
singleResponse, err := sendStream.CloseAndRecv()
if err != nil {
log.Fatalf("3. 服务端响应异常 : %v", err)
return err
}
// 将服务端的返回信息打印出来
log.Printf("response, id : %d, name : %s", singleResponse.GetId(), singleResponse.GetName())
return nil
}
func multiReqMultiResp(ctx context.Context, client pb.IGrpcStremserviceClient) error {
// 远程调用
intOutStream, err := client.MultiReqMultiResp(ctX)
if err != nil {
log.Fatalf("4. 远程调用异常 : %v", err)
return err
}
// 发送多条记录到服务端
for i:=0; i<10; i++ {
if err = intOutStream.Send(&pb.Singlerequest{Id: int32(400+i)}); err!=nil {
log.Fatalf("4. 通过流发送数据异常 : %v", err)
return err
}
}
// 服务端一直在接收,直到收到io.EOF为止
// 因此,这里必须发送io.EOF到服务端,让服务端知道发送已经结束(很重要)
intOutStream.CloseSend()
// 接收服务端发来的数据
for {
singleResponse, err := intOutStream.Recv()
if err == io.EOF {
log.Printf("4. 获取数据完毕")
break
} else if err != nil {
log.Fatalf("4. 接收服务端数据异常 : %v", err)
break
}
log.Printf("4. 收到服务端响应, id : %d, name : %s", singleResponse.GetId(), singleResponse.GetName())
}
return nil
}
[golang@centos7 client]$ go run client.go
2020/12/13 21:39:35 测试单一请求应答,一对一
2020/12/13 21:39:35 response, id : 101, name : 1. name-101
2020/12/13 21:39:35 测试服务端流式应答,一对多
2020/12/13 21:39:35 2. 收到服务端响应, id : 0, name : 2. name-0
2020/12/13 21:39:35 2. 收到服务端响应, id : 1, name : 2. name-1
2020/12/13 21:39:35 2. 收到服务端响应, id : 2, name : 2. name-2
2020/12/13 21:39:35 2. 收到服务端响应, id : 3, name : 2. name-3
2020/12/13 21:39:35 2. 收到服务端响应, id : 4, name : 2. name-4
2020/12/13 21:39:35 2. 收到服务端响应, id : 5, name : 2. name-5
2020/12/13 21:39:35 2. 收到服务端响应, id : 6, name : 2. name-6
2020/12/13 21:39:35 2. 收到服务端响应, id : 7, name : 2. name-7
2020/12/13 21:39:35 2. 收到服务端响应, id : 8, name : 2. name-8
2020/12/13 21:39:35 2. 收到服务端响应, id : 9, name : 2. name-9
2020/12/13 21:39:35 2. 获取数据完毕
2020/12/13 21:39:35 测试客户端流式请求,多对一
2020/12/13 21:39:35 response, id : 3045, name : 3. name-3045
2020/12/13 21:39:35 测试双向流式请求应答,多对多
2020/12/13 21:39:35 4. 收到服务端响应, id : 400, name : 4. name-400
2020/12/13 21:39:35 4. 收到服务端响应, id : 401, name : 4. name-401
2020/12/13 21:39:35 4. 收到服务端响应, id : 402, name : 4. name-402
2020/12/13 21:39:35 4. 收到服务端响应, id : 403, name : 4. name-403
2020/12/13 21:39:35 4. 收到服务端响应, id : 404, name : 4. name-404
2020/12/13 21:39:35 4. 收到服务端响应, id : 405, name : 4. name-405
2020/12/13 21:39:35 4. 收到服务端响应, id : 406, name : 4. name-406
2020/12/13 21:39:35 4. 收到服务端响应, id : 407, name : 4. name-407
2020/12/13 21:39:35 4. 收到服务端响应, id : 408, name : 4. name-408
2020/12/13 21:39:35 4. 收到服务端响应, id : 409, name : 4. name-409
2020/12/13 21:39:35 4. 获取数据完毕
2020/12/13 21:39:35 测试完成
[golang@centos7 server]$ go run server.go
2020/12/13 21:29:19 开始监听,等待远程调用...
2020/12/13 21:39:35 1. 收到请求: 101
2020/12/13 21:39:35 2. 收到请求: 201
2020/12/13 21:39:35 3. 收到请求: 300
2020/12/13 21:39:35 3. 收到请求: 301
2020/12/13 21:39:35 3. 收到请求: 302
2020/12/13 21:39:35 3. 收到请求: 303
2020/12/13 21:39:35 3. 收到请求: 304
2020/12/13 21:39:35 3. 收到请求: 305
2020/12/13 21:39:35 3. 收到请求: 306
2020/12/13 21:39:35 3. 收到请求: 307
2020/12/13 21:39:35 3. 收到请求: 308
2020/12/13 21:39:35 3. 收到请求: 309
2020/12/13 21:39:35 3. 客户端发送完毕
2020/12/13 21:39:35 4. 接收到数据 400
2020/12/13 21:39:35 4. 接收到数据 401
2020/12/13 21:39:35 4. 接收到数据 402
2020/12/13 21:39:35 4. 接收到数据 403
2020/12/13 21:39:35 4. 接收到数据 404
2020/12/13 21:39:35 4. 接收到数据 405
2020/12/13 21:39:35 4. 接收到数据 406
2020/12/13 21:39:35 4. 接收到数据 407
2020/12/13 21:39:35 4. 接收到数据 408
2020/12/13 21:39:35 4. 接收到数据 409
2020/12/13 21:39:35 4. 接收完毕
以上是大佬教程为你收集整理的gRPC学习之四:实战四类服务方法全部内容,希望文章能够帮你解决gRPC学习之四:实战四类服务方法所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。