首页 > 编程语言 >在C++中使用gRPC框架

在C++中使用gRPC框架

时间:2024-07-12 16:42:11浏览次数:11  
标签:框架 gRPC C++ 二进制 序列化 数据 服务端 客户端

概览

在gRPC里客户端应用可以像调用本地对象一样直接调用另一台不同机器上的服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多RPC系统类似,gRPC也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包括参数和返回类型) 。在服务器端实现这个接口,并运行一个gRPC服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。

gRPC客户端和服务端可以在多种环境中运行和交互-从google内部的服务器到你自己的笔记本,并且可以用任何gRPC支持的语言来编写。所以,你可以很容易地用Java创建一个gRPC服务端,用Go、Python、Ruby来创建客户端。此外,Google最新API将有gRPC版本的接口,使你容易地将Google的功能集成到你的应用里。

使用protocol buffers

gRPC默认使用protocol buffers,这是Google开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如JSON)。正如你将在下方例子里所看到的,你用proto files创建gRPC服务,用protocol buffers消息类型来定义方法的参数和返回类型。你可以在Protocol Buffers文档中找到更多关于Protocol Buffers的资料。

定义服务

创建我们的例子的第一步是定义服务:一个RPC服务通过参数和返回类型来指定可以远程调用的方法。可以使用Protocol Buffers接口定义语言来定义服务方法。

例如:examples/cpp/helloworld

syntax = "proto3";

option java_package = "io.grpc.examples.helloworld";
option java_multiple_files = true;
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}

  rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {}

  rpc SayHelloBidiStream (stream HelloRequest) returns (stream HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

一旦定义好服务,我们可以使用Protocol Buffers编译器protoc​来生成创建应用所需的特定客户端和服务端的代码---你可以生成任意gRPC支持的语言的代码。生成的代码包括客户端的存根和服务器要实现的抽象接口,均包含Greeter​所定义的方法。

以Java为例:

服务端需要实现以下接口

public static interface Greeter {
	public void sayHello(Helloworld.HelloRequest request, StreamObserver<Helloworld.HelloReply> responseObserver);
}

而客户端用来与Greeter​服务端进行对话的存根​类。就像你看到的,异步存根也实现了Greeter​接口。

public static class GreeterStub extends AbstractStub<GreeterStub>
    implements Greeter {
      ...
    }

如果是C++的话,则需要使用以下步骤:

生成客户端和服务端接口,运行:

$ make helloworld.grpc.pb.cc helloworld.pb.cc

数据序列化

在gRPC中,数据的序列化是一个核心概念,它涉及到将数据结构或对象转换成一种可以在网络中传输或存储的格式(通常是二进制格式) 。这个过程确保了数据在发送方和接收方之间能够准确无误地传递。下面我将详细解释数据的序列化,并给出具体例子。

如果我们要支持不同语言的数据序列化,就需要在不同语言之上搭建一个协议用来屏蔽不同语言、不同机器的实现细节。

所以,想要实现不同语言、不同机器间的交流,为不同语言搭建数据序列化的抽象层是有必要的。

一、什么是数据的序列化

序列化(Serialization) 是指将数据结构或对象状态转换为可以存储或传输的形式的过程。具体来说,就是将数据结构或对象转换成一串字节(即二进制数据流),以便在网络上传输或保存到本地文件中。序列化后的数据保留了原始数据的结构和内容,但转换成了更适合存储或传输的格式。

至于序列化之后产生的格式该怎么被接收方理解,那就必须接收方也会这种序列化方式。

双方都会数据的序列化算法,才能真正理解传输的数据格式。

二、序列化的目的

  1. 数据交换:序列化后的数据可以在不同的系统或平台之间进行交换,因为数据以通用的二进制格式表示。
  2. 网络传输:在网络通信中,数据需要被序列化成二进制格式才能在网络上传输。
  3. 数据存储:序列化后的数据可以保存到文件中,以便在需要时重新加载到内存中。

三、gRPC中的序列化

在gRPC中,通常使用Protocol Buffers(简称Protobuf)作为序列化协议(就是数据序列化的一种实现) 。Protobuf是一种轻便高效的结构化数据存储格式,它基于二进制编码构建,能够减少CPU的复杂解析,从而保障RPC调用的高性能。

四、序列化的例子

假设我们有一个简单的用户信息数据结构,包含用户的ID、姓名和年龄,我们可以使用Protobuf来定义这个数据结构并进行序列化。

1. 定义数据结构(.proto文件)

syntax = "proto3";

message User {
  int32 id = 1;
  string name = 2;
  int32 age = 3;
}

在这个.proto​文件中,我们定义了一个User​消息,它包含三个字段:id​(整型)、name​(字符串)和age​(整型)。

2. 序列化过程

当我们需要将一个User​对象(比如User{id: 1, name: "Alice", age: 30}​)序列化时,Protobuf编译器会根据.proto​文件的定义,将这个对象转换成一串二进制字节。这个过程中,Protobuf会采用高效的编码方式(如Varint、Zigzag等)来压缩数据,以减少序列化后的数据大小。

id = 1, name = 2, age = 3这的数字应该是定义变量的二进制形式的排列顺序,转换成真正的二进制字节序列后,为了高效传输,还需要进行压缩(大家约定好算法)。

3. 反序列化过程

接收方在收到序列化后的二进制数据后,会使用Protobuf编译器生成的反序列化代码,将二进制数据转换回User​对象。这样,接收方就能得到与发送方完全相同的User​对象,并进行后续处理。

接收到序列化后的数据后,将这些二进制的序列化数据转换成本地语言、本地机器所使用的状态,这是通过本地的ProtoBuf来处理的。

五、总结

数据的序列化是将数据结构或对象转换成二进制字节流的过程,它在gRPC等RPC框架中扮演着至关重要的角色。通过序列化,数据可以在不同的系统、平台或语言之间进行交换和传输,从而实现远程通信和数据共享。在gRPC中,Protobuf作为一种高效、轻便的序列化协议,被广泛应用于数据的序列化和反序列化过程中。

标签:框架,gRPC,C++,二进制,序列化,数据,服务端,客户端
From: https://www.cnblogs.com/Aderversa/p/18298809

相关文章

  • 发布用flask框架开发的python后端程序到windows服务器
    flask框架开发的python后端程序开发好了后,怎么发布到生产环境呢?以app.run()的方式在生产环境上启动服务,当有异常特别容易退出,而且性能很弱。生产环境下,python常见的web部署搭配是nginx+gunicorn。但是这种搭配只适合在Linux环境下。gunicorn不支持windows环境。如果要搭......
  • C/C++ 避免空指针解引用的方法
    在C/C++中,空指针解引用是一个常见的问题,它会导致程序崩溃或未定义行为。为了避免这种情况,可以采取以下几种方法来确保指针在使用前是有效的:1.初始化指针确保所有指针在使用前都被初始化。未初始化的指针可能包含任意值,尝试解引用这样的指针是危险的。int*ptr=nullptr;......
  • 【C++11新特性】在定义静态成员变量的同时进行初始化
    //test.hclasstest{public:test()=delete;~test()=delete;private:staticconstexprlonglongPOLY_64_REV=0x95AC9329AC4BC9B5L;staticconstexprintBITS_PER_BYTE=8;staticconstexprintCRC_TABLE_LENGTH=256;staticlon......
  • 【C++修行之道】string类的使用
    目录一.C语言中的字符串二、标准库中的string类(了解)2.1string类(了解)2.2帮助文档阅读三、string类的常用接口说明3.1 string类对象的常见构造 3.2 string类对象的容量操作3.3 string类对象的访问及遍历操作字符串类的简单实现3.4 string类对象的修改操作......
  • 2024年华为OD机试真题-传递悄悄话-C++-OD统一考试(C卷D卷)
    2024年OD统一考试(D卷)完整题库:华为OD机试2024年最新题库(Python、JAVA、C++合集) 题目描述:给定一个二叉树,每个节点上站着一个人,节点数字表示父节点到该节点传递悄悄话需要花费的时间。初始时,根节点所在位置的人有一个悄悄话想要传递给其他人,求二叉树所有节点上的人都接收到悄......
  • C++ 多态
    1.多态的概念多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。比如买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。2.多态的定义及实现2.1 虚函数虚函数:即被virtu......
  • 解决若依框架与tailwindcss 样式冲突问题
    首先下载tailwindcss样式https://www.tailwindcss.cn/docs/installation我们可以按照官方文档来进行配置 npminstall-Dtailwindcssnpxtailwindcssinit /**@type{import('tailwindcss').Config}*/module.exports={content:["./src/**/*.{html,js}"],the......
  • How to ues Dev C++
    对于Dev-C++这个"老古董",合理利用设置去提升它的能力,是非常important重要的。1.打开全警告方式:工具[T]->编译选项[C]->代码生成/优化->代码警告->第二个和第三个选Yes代码里,总是会出现奇奇怪怪的错误(scanf、printf占位符和参数列表不匹配,if里把==打成=,运算符优先级.........
  • 一些 C++ 的卡常技巧
    是的,这篇文章的主要内容非常好懂,相信各位同学也十分感兴趣毕竟哪位OIer不想自己的代码跑得飞快呢?那么我们就进入正题吧!First众所周知,一份代码里面必然会有很多循环打表的话当我没说,而循环自然是十分占时间的。所以我们要做的就十分清楚了:加速循环!1.把int改成registerin......
  • <c++>斗破苍穹游戏(转载·博客园)喜欢的一键三连~
    #include<stdio.h>#include<ctime>#include<time.h>//suiji#include<windows.h>//SLEEP函数structPlayer//玩家结构体,并初始化player{charname[21];intattack;intdefense;inthealth;longintmax_health;intlevel;intexp;intrange_exp;......