grpc使用教程

grpc是google开源的rpc框架,默认使用protobuf序列化格式

本文介绍grpc使用的全过程,包括:

1.proto文件设计和编写

2.使用protoc编译器生成代码框架(包含接口定义)

3.根据生成的框架代码自己实现服务端和客户端的逻辑(重写框架中定义的接口)

一、proto文件

我们使用protobuf序列化格式,这个由谷歌设计的协议旨在提供高效的序列化机制,支持高性能服务

设计一个注册和登录的服务
syntax = "proto3";  // protoc版本
package IM.Login;   // 命名空间: 项目名.模块名

// 定义服务类型,关键字:service
service ImLogin {
   rpc Regist(IMRegistReq) returns (IMRegistRes) {}     // 使用rpc关键字 
   rpc Login(IMLoginReq) returns (IMLoginRes) {}        // 与普通函数定义类似,Login是函数名,IMLoginReq是参数,returns是返回值
}

// 定义注册类型,关键字:message
message IMRegistReq{
    string user_name = 1; // 这里变量 user_name = 1 并不是赋值,1表示变量的编号,用于两端互相解析数据,下文同理  
    string password = 2; 
}
// 注册返回
message  IMRegistRes{
    string user_name = 1; 
    uint32 user_id = 2; 
    uint32 result_code = 3; // 返回0的时候注册注册
}
// 登录请求
message IMLoginReq{
    string user_name = 1; 
    string password = 2; 
}
// 登录返回
message  IMLoginRes{
    uint32 user_id = 1; 
    uint32 result_code = 2; 
}

二、使用protoc编译器生成框架代码

编译命令:

protoc --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=/usr/local/bin/grpc_cpp_plugin IM.Login.proto

生成C++代码IM.Login.pb.h和IM.Login.pb.cc, IM.Login.grpc.pb.h和IM.Login.grpc.pb.cc

从.proto文件生成了什么?

当用protocol buffer编译器来运行.proto文件时,编译器将生成所选择语言的代码,这些代码可以操作在.proto文件中定义的消息 类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。

1.对C++来说,编译器会为每个.proto文件生成一个.h文件和一个.cc文件,.proto文件中的每一个消息有一个对应的类。

2.对Java来说,编译器为每一个消息类型生成了一个.java文件,以及一个特殊的Builder类(该类是用来创建消息类接口 的)。

3.对Python来说,有点不太一样——Python编译器为.proto文件中的每个消息类型生成一个含有静态描述符的模块,,该模块 与一个元类(metaclass)在运行时(runtime)被用来创建所需的Python数据访问类。

4.对go来说,编译器会位每个消息类型生成了一个.pd.go文件。

5.对于Ruby来说,编译器会为每个消息类型生成了一个.rb文件。

6.javaNano来说,编译器输出类似域java但是没有Builder类

7.对于Objective­C来说,编译器会为每个消息类型生成了一个pbobjc.h文件和pbobjcm文件,.proto文件中的每一个消息有一个 对应的类。

8.对于C#来说,编译器会为每个消息类型生成了一个.cs文件,.proto文件中的每一个消息有一个对应的类。

三、根据生成的框架代码自己实现服务端和客户端的逻辑

这是根据.proto文件生成的代码目录:

在这里插入图片描述

我们需要根据这些文件中提供的接口定义,来实现服务端代码的逻辑,有两个步骤

1.实现接口函数

2.根据接口实现业务逻辑

服务端代码
1.实现接口函数

首先创建server.cc文件,定义头文件,开放命名空间:

#include <iostream>
#include <string>

// grpc头文件
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>

// 包含我们自己proto文件生成的.h
#include "IM.Login.pb.h"
#include "IM.Login.grpc.pb.h"

// 命名空间
// grcp
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
// 自己proto文件的命名空间
using IM::Login::ImLogin;
using IM::Login::IMRegistReq;
using IM::Login::IMRegistRes;
using IM::Login::IMLoginReq;
using IM::Login::IMLoginRes;

声明一个自定义类,继承自.grpc.pb.h文件中的service类:

并实现其中的虚函数

class IMLoginServiceImpl : public ImLogin::Service {
    // 注册
    virtual  Status Regist(ServerContext* context, const IMRegistReq* request, IMRegistRes* response) override {
        std::cout << "Regist user_name: " << request->user_name() << std::endl;

        response->set_user_name(request->user_name());
        response->set_user_id(10);
        response->set_result_code(0);

        return Status::OK;
    }
 
    // 登录
    virtual  Status Login(ServerContext* context, const IMLoginReq* request, IMLoginRes* response) override {
        std::cout << "Login user_name: " << request->user_name() << std::endl;
        response->set_user_id(10);
        response->set_result_code(0);
        return Status::OK;
    }
  
};

最后,实现业务逻辑,绑定ip+port,进行服务监听

void RunServer() 
{
    std::string server_addr("0.0.0.0:50051");

    // 创建一个服务类
    IMLoginServiceImpl service;
  
    ServerBuilder builder;

    builder.AddListeningPort(server_addr, grpc::InsecureServerCredentials());
    builder.AddChannelArgument(GRPC_ARG_KEEPALIVE_TIME_MS, 5000);
    builder.AddChannelArgument(GRPC_ARG_KEEPALIVE_TIMEOUT_MS, 10000);
    builder.AddChannelArgument(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, 1);
    builder.RegisterService(&service);
   
    //创建/启动
    std::unique_ptr<Server> server(builder.BuildAndStart());
    std::cout << "Server listening on " << server_addr << std::endl;
    // 进入服务循环
    server->Wait();
}

int main(int argc, const char** argv)
{
    RunServer();
    return 0;
}
客户端代码

首先创建client.cc文件,声明头文件,开放命名空间:

#include <iostream>
#include <memory>
#include <string>
// /usr/local/include/grpcpp/grpcpp.h
#include <grpcpp/grpcpp.h>

// 包含我们自己proto文件生成的.h
#include "IM.Login.pb.h"
#include "IM.Login.grpc.pb.h"

// 命名空间
// grcp
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
// 自己proto文件的命名空间
using IM::Login::ImLogin;
using IM::Login::IMRegistReq;
using IM::Login::IMRegistRes;
using IM::Login::IMLoginReq;
using IM::Login::IMLoginRes;

实现客户端逻辑:

class ImLoginClient
{
public:
    ImLoginClient(std::shared_ptr<Channel> channel)
        :stub_(ImLogin::NewStub(channel)) {

    }
    void Regist(const std::string &user_name, const std::string &password) {
        IMRegistReq request;
        request.set_user_name(user_name);
        request.set_password(password);
        
        IMRegistRes response;
        ClientContext context;
        std::cout <<  "-> Regist req" << std::endl;
        Status status = stub_->Regist(&context, request, &response);
        if(status.ok()) {
            std::cout <<  "user_name:" << response.user_name() << ", user_id:" << response.user_id() << std::endl;
        } else {
            std::cout <<  "user_name:" << response.user_name() << "Regist failed: " << response.result_code()<< std::endl;
        }
    }

     void Login(const std::string &user_name, const std::string &password) {
        IMLoginReq request;
        request.set_user_name(user_name);
        request.set_password(password);
        
        IMLoginRes response;
        ClientContext context;
        std::cout <<  "-> Login req" << std::endl;
        Status status = stub_->Login(&context, request, &response);
        if(status.ok()) {
            std::cout <<  "user_id:" << response.user_id() << " login ok" << std::endl;
        } else {
            std::cout <<  "user_name:" << request.user_name() << "Login failed: " << response.result_code()<< std::endl;
        }
    }

private:
    std::unique_ptr<ImLogin::Stub> stub_;
};

int main() 
{
    // 服务器的地址
    std::string server_addr = "localhost:50051";
    ImLoginClient im_login_client(
        grpc::CreateChannel(server_addr, grpc::InsecureChannelCredentials())
    );
    std::string user_name = "wjq++";
    std::string password = "123456";
    im_login_client.Regist(user_name, password);
    im_login_client.Login(user_name, password);

    return 0;
}

推荐学习 https://xxetb.xetslk.com/s/p5Ibb

### 回答1: 很高兴为您提供帮助!关于Go语言中的GRPC教程,您可以参考Go官方文档中的GRPC教程:https://grpc.io/docs/tutorials/basic/go/,也可以参考GitHub上的一些开源项目,如https://github.com/grpc/grpc-go。 ### 回答2: Golang的GRPC教程是关于如何使用Google开发的gRPC框架来构建高效的分布式系统的指南。GRPC是一种远程过程调用(RPC)框架,主要用于在客户端和服务器之间进行通信。 Golang的GRPC教程首先介绍了GRPC的基本概念和原理,例如客户端和服务器之间的通信方式以及如何定义服务和消息。然后,教程详细介绍了如何在Golang中安装和配置GRPC的软件开发工具包,并提供了一些示例代码来说明如何创建GRPC服务器和客户端。 接下来,教程会教你如何使用protobuf(Protocol Buffers)作为GRPC的数据格式,protobuf是一种轻量级且语言无关的数据序列化机制。你将学会如何定义消息和服务接口,以及如何使用protobuf生成Golang的代码。 在教程的后半部分,你将学习如何使用GRPC的不同功能,如流式传输、服务器端流式和客户端流式,以及双向流式。这些功能可以让你更灵活地设计和实现你的分布式系统。 此外,教程还涉及了如何使用拦截器(interceptors)来实现自定义的认证、日志记录和错误处理等功能。你将了解如何在GRPC中实现服务端和客户端的拦截器,并掌握如何在应用程序中使用它们。 最后,教程还会介绍一些关于GRPC的最佳实践,例如如何处理错误、优化性能和处理并发等问题。这些实践可以帮助你在开发和维护GRPC应用程序时更高效和可靠。 总之,Golang的GRPC教程提供了一种简单且强大的方式来构建分布式系统,并为你提供了充足的示例代码和实践经验来帮助你理解和应用GRPC框架。无论是初学者还是有经验的开发者,都能受益于这个教程。 ### 回答3: Golang的GRPC教程是介绍Go语言中的GRPC框架的教程。GRPC是一种高性能、开源的远程过程调用(RPC)框架,支持多种编程语言,包括Go语言。 在GRPC教程中,首先会介绍GRPC的基本概念和架构。GRPC使用Protocol Buffers(简称Protobuf)作为接口定义语言(IDL),用于定义服务接口和消息格式。它提供了强类型的接口定义和支持多种语言的代码生成工具。通过IDL的定义,可以自动生成客户端和服务器端代码,大大简化了跨服务通信的开发工作。 接下来的教程将详细介绍如何使用GRPC构建客户端和服务器端。通过定义GRPC服务的接口和消息格式,可以方便地在不同的服务之间进行通信。教程会演示如何编写服务器端代码,实现服务接口的具体逻辑,并将其注册到GRPC框架中。同时,还会演示如何编写客户端代码,通过GRPC调用服务器端提供的服务,并处理返回的结果。 GRPC教程还会介绍一些高级特性,例如流式处理、认证和安全性等。流式处理支持客户端流、服务器端流和双向流,可以实现更复杂的通信模式。认证和安全性可以通过TLS/SSL等机制来保护通信的安全性。 在学习GRPC教程时,你将会了解到GRPC的优势和如何使用GRPC来构建可扩展和高性能的分布式系统。通过GRPC,你可以轻松地实现跨语言的服务调用,并利用其丰富的特性来满足不同的业务需求。 总之,Golang的GRPC教程是一个很好的学习资源,能够帮助你掌握GRPC框架的基本概念和使用方法,并在实际项目中应用它来构建高效可靠的分布式系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wjq++

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值