2024年Go最新Go语言:gRPC调用_go语言调用grpc(2),2024年最新头条Golang面试题

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

type OrderService_GetOrderInfosClient interface {
Recv() (*OrderInfo, error)
grpc.ClientStream
}

type orderServiceGetOrderInfosClient struct {
grpc.ClientStream
}

func (x *orderServiceGetOrderInfosClient) Recv() (*OrderInfo, error) {
m := new(OrderInfo)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}


流模式下,服务接口的客户端提供Recv()方法接收服务端发送的流数据。


#### 1.4 服务编码实现


定义好服务接口并编译生成代码文件后,即可根据规则对定义的服务进行编码实现。具体的服务编码实现如下所示:



//订单服务实现
type OrderServiceImpl struct {
}

//获取订单信息s
func (os *OrderServiceImpl) GetOrderInfos(request *message.OrderRequest, stream message.OrderService_GetOrderInfosServer) error {
fmt.Println(" 服务端流 RPC 模式")

orderMap := map[string]message.OrderInfo{
    "201907300001": message.OrderInfo{OrderId: "201907300001", OrderName: "衣服", OrderStatus: "已付款"},
    "201907310001": message.OrderInfo{OrderId: "201907310001", OrderName: "零食", OrderStatus: "已付款"},
    "201907310002": message.OrderInfo{OrderId: "201907310002", OrderName: "食品", OrderStatus: "未付款"},
}
for id, info := range orderMap {
    if (time.Now().Unix() >= request.TimeStamp) {
        fmt.Println("订单序列号ID:", id)
        fmt.Println("订单详情:", info)
        //通过流模式发送给客户端
        stream.Send(&info)
    }
}
return nil

}


GetOrderInfos方法就是服务接口的具体实现,因为是流模式开发,服务端将数据以流的形式进行发送,因此,该方法的第二个参数类型为OrderService\_GetOrderInfosServer,该参数类型是一个接口,其中包含Send方法,允许发送流数据。Send方法的具体实现在编译好的pb.go文件中,进一步调用grpc.SeverStream.SendMsg方法。


#### 1.5 服务的注册和监听的处理


服务的监听与处理与前文所学内容没有区别,依然是相同的步骤:



func main() {
server := grpc.NewServer()
//注册
message.RegisterOrderServiceServer(server, new(OrderServiceImpl))
lis, err := net.Listen(“tcp”, “:8090”)
if err != nil {
panic(err.Error())
}
server.Serve(lis)
}


#### 1.6 客户端数据接收


服务端使用Send方法将数据以流的形式进行发送,客户端可以使用Recv()方法接收流数据,因为数据流失源源不断的,因此使用for无限循环实现数据流的读取,当读取到io.EOF时,表示流数据结束。客户端数据读取实现如下:




for {
orderInfo, err := orderInfoClient.Recv()
if err == io.EOF {
fmt.Println(“读取结束”)
return
}
if err != nil {
panic(err.Error())
}
fmt.Println(“读取到的信息:”, orderInfo)
}


#### 1.7 运行结果


按照先后顺序,依次运行server.go文件和client.go文件,可以得到运行结果。


#### 1.7.1 服务端运行结果



服务端流 RPC 模式
订单序列号ID: 201907300001
订单详情: {201907300001 衣服 已付款 {} [] 0}
订单序列号ID: 201907310001
订单详情: {201907310001 零食 已付款 {} [] 0}
订单序列号ID: 201907310002
订单详情: {201907310002 食品 未付款 {} [] 0}


#### 1.7.2 客户端运行结果



客户端请求RPC调用:服务端流模式
读取到的信息: OrderId:“201907310001” OrderName:“\351\233\266\351\243\237” OrderStatus:“\345\267\262\344\273\230\346\254\276”
读取到的信息: OrderId:“201907310002” OrderName:“\351\243\237\345\223\201” OrderStatus:“\346\234\252\344\273\230\346\254\276”
读取到的信息: OrderId:“201907300001” OrderName:“\350\241\243\346\234\215” OrderStatus:“\345\267\262\344\273\230\346\254\276”
读取结束


### 二 客户端流模式


上文演示的是服务端以数据流的形式返回数据的形式。对应的,也存在客户端以流的形式发送请求数据的形式。


#### 2.1 服务接口的定义


与服务端同理,客户端流模式的RPC服务声明格式,就是使用stream修饰服务接口的接收参数,具体如下所示:




//订单服务service定义
service OrderService {
rpc AddOrderList (stream OrderRequest) returns (OrderInfo) {}; //客户端流模式
}


#### 2.2 编译.proto文件


使用编译命令编译.protow文件。客户端流模式中也会自动生成服务接口的接口。


#### 2.2.1 自动生成的服务流接口实现



type OrderService_AddOrderListServer interface {
SendAndClose(*OrderInfo) error
Recv() (*OrderRequest, error)
grpc.ServerStream
}

type orderServiceAddOrderListServer struct {
grpc.ServerStream
}

func (x *orderServiceAddOrderListServer) SendAndClose(m *OrderInfo) error {
return x.ServerStream.SendMsg(m)
}

func (x *orderServiceAddOrderListServer) Recv() (*OrderRequest, error) {
m := new(OrderRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}


SendAndClose和Recv方法是客户端流模式下的服务端对象所拥有的方法。


#### 2.2.2 自动生成的客户端流接口实现



type OrderService_AddOrderListClient interface {
Send(*OrderRequest) error
CloseAndRecv() (*OrderInfo, error)
grpc.ClientStream
}

type orderServiceAddOrderListClient struct {
grpc.ClientStream
}

func (x *orderServiceAddOrderListClient) Send(m *OrderRequest) error {
return x.ClientStream.SendMsg(m)
}

func (x *orderServiceAddOrderListClient) CloseAndRecv() (*OrderInfo, error) {
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
m := new(OrderInfo)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}


Send和CloseAndRecv是客户端流模式下的客户端对象所拥有的方法。


#### 2.3 服务的实现


客户端流模式的服务接口具体实现如下:



//订单服务实现
type OrderServiceImpl struct {
}

//添加订单信息服务实现
func (os *OrderServiceImpl) AddOrderList(stream message.OrderService_AddOrderListServer) error {
fmt.Println(" 客户端流 RPC 模式")

for {
    //从流中读取数据信息
    orderRequest, err := stream.Recv()
    if err == io.EOF {
        fmt.Println(" 读取数据结束 ")
        result := message.OrderInfo{OrderStatus: " 读取数据结束 "}
        return stream.SendAndClose(&result)
    }
    if err != nil {
        fmt.Println(err.Error())
        return err
    }
    //打印接收到的数据
    fmt.Println(orderRequest)
}

}


#### 2.4 服务的注册和监听处理


依然是采用相同的服务注册和监听处理方式对服务进行注册和监听处理。



func main() {

server := grpc.NewServer()
//注册
message.RegisterOrderServiceServer(server, new(OrderServiceImpl))

lis, err := net.Listen("tcp", ":8090")
if err != nil {
    panic(err.Error())
}
server.Serve(lis)

}


#### 2.5 客户端实现


客户端调用send方法流数据到服务端,具体实现如下:




//调用服务方法
addOrderListClient, err := orderServiceClient.AddOrderList(context.Background())
if err != nil {
panic(err.Error())
}
//调用方法发送流数据
for _, info := range orderMap {
err = addOrderListClient.Send(&info)
if err != nil {
panic(err.Error())
}
}

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

[外链图片转存中…(img-hvm4H6mb-1715382045713)]
[外链图片转存中…(img-6Cg9GzH1-1715382045713)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值