后台技术gRPC基础概念详解

本文介绍gRPC的基础概念。首先通过关系图直观展示这些基础概念之间关联,介绍异步gRPC的Server和Client的逻辑;然后介绍RPC的类型,阅读和抓包分析gRPC的通信过程协议,gRPC上下文;最后分析grpc.pb.h文件的内容,包括Stub的能力、Service的种类以及与核心库的关系。

之所以谓之基础,是这些内容基本不涉及gRPCCore的内容。

上图中列出了gRPC基础概念及其关系图。其中包括:Service(定义)、RPC、API、Client、Stub、Channel、Server、Service(实现)、ServiceBuilder等。

接下来,以官方提供的example/helloworld为例进行说明。

.proto文件定义了服务Greeter和APISayHello:

classGreeterClient是Client,是对Stub封装;通过Stub可以真正的调用RPC请求。

Channel提供一个与特定gRPCserver的主机和端口建立的连接。

Stub就是在Channel的基础上创建而成的。

Server端需要实现对应的RPC,所有的RPC组成了Service:

Server的创建需要一个Builder,添加上监听的地址和端口,注册上该端口上绑定的服务,最后构建出Server并启动:

RPC和API的区别:RPC(RemoteProcedureCall)是一次远程过程调用的整个动作,而API(ApplicationProgrammingInterface)是不同语言在实现RPC中的具体接口。一个RPC可能对应多种API,比如同步的、异步的、回调的。一次RPC是对某个API的一次调用,比如:

不管是哪种类型RPC,都是由Client发起请求。

Client看文档可以理解,但Server的代码复杂,文档和注释中的解释并不是很好理解,接下来会多做一些解释。

1.异步Client

greeter_async_client.cc中是异步Client的Demo,其中只有一次请求,逻辑简单。

stub_->PrepareAsyncSayHello()+rpc->StartCall()

stub_->AsyncSayHello()

2.异步Server

RequestSayHello()这个函数没有任何的说明。只说是:"we*request*thatthesystemstartprocessingSayHellorequests."也没有说跟cq_->Next(&tag,&ok);的关系。我这里通过加上一些日志打印,来更清晰的展示Server的逻辑:

上边绿色的部分为创建的第一个CallData对象地址,橙色的为第二个CallData的地址。

传入ServerContextctx_

传入HelloRequestrequest_

传入ServerAsyncResponseWriterresponder_

传入ServerCompletionQueue*cq_

将对象自身的地址作为tag传入

该动作,能将事件加入事件循环,可以在CompletionQueue中等待

创建新的CallData对象以接收新请求

处理消息体并设置reply_

将状态设置为FINISH

调用responder_.Finish()将返回发送给客户端

该动作,能将事件加入到事件循环,可以在CompletionQueue中等待

3.关系图

将上边的异步Client和异步Server的逻辑通过关系图进行展示。右侧RPC为创建的对象中的内存容,左侧使用相同颜色的小块进行代替。

以下CallData并非gRPC中的概念,而是异步Server在实现过程中为了方便进行的封装,其中的Status也是在异步调用过程中自定义的、用于转移的状态。

4.异步Client2

在example/cpp/helloworld中还有另外一个异步Client,对应文件名为greeter_async_client2.cc。这个例子中使用了两个线程去分别进行发送请求和处理返回,一个线程批量发出100个SayHello的请求,另外一个不断的通过cq_.Next()来等待返回。

无论是Client还是Server,在以异步方式进行处理时,都要预先分配好一定的内存/对象,以存储异步的请求或返回。

5.回调方式的异步调用

使用回调方式简介明了,结构上与同步方式相差不多,但是并发有本质的区别。可以通过文件对比,来查看其中的差异。

其实,回调方式的异步调用属于实验性质的,不建议直接在生产环境使用,这里也只做简单的介绍:

5.1回调Client

发送单个请求,在调用SayHello时,除了传入Request、Reply的地址之外,还需要传入一个接收Status的回调函数。

例子中只有一个请求,因此在SayHello之后,就直接通过condition_variable的wait函数等待回调结束,然后进行后续处理。这样其实不能进行并发,跟同步请求差别不大。如果要进行大规模的并发,还是需要使用额外的对象进行封装一下。

5.2回调Server

与同步Server不同的是:

可以按照Client和Server一次发送/返回的是单个消息还是多个消息,将gRPC分为:

1.Server对RPC的实现

Server需要实现proto中定义的RPC,每种RPC的实现都需要将ServerContext作为参数输入。

如果是一元(Unary)RPC调用,则像调用普通函数一样。将Request和Reply的对象地址作为参数传入,函数中将根据Request的内容,在Reply的地址上写上对应的返回内容。

如果涉及到流,则会用Reader或/和Writer作为参数,读取流内容。如ServerStream模式下,只有Server端产生流,这时对应的Server返回内容,需要使用作为参数传入的ServerWriter。这类似于以'w'打开一个文件,持续的往里写内容,直到没有内容可写关闭。

另一方面,Client来的流,Server需要使用一个ServerReader来接收。这类似于打开一个文件,读其中的内容,直到读到EOF为止类似。

如果Client和Server都使用流,也就是Bidirectional-Stream模式下,输入参数除了ServerContext之外,只有一个ServerReaderWriter指针。通过该指针,既能读Client来的流,又能写Server产生的流。

例子中,Server不断地从stream中读,读到了就将对应的写过写到stream中,直到客户端告知结束;Server处理完所有数据之后,直接返回状态码即可。

2.Client对RPC的调用

Client在调用一元(Unary)RPC时,像调用普通函数一样,除了传入ClientContext之外,将Request和Response的地址,返回的是RPC状态:

Client在调用ServerStreamRPC时,不会得到状态,而是返回一个ClientReader的指针:

Reader通过不断的Read(),来不断的读取流,结束时Read()会返回false;通过调用Finish()来读取返回状态。

调用ClientStreamRPC时,则会返回一个ClientWriter指针:

Writer会不断的调用Write()函数将流中的消息发出;发送完成后调用WriteDone()来说明发送完毕;调用Finish()来等待对端发送状态。

而双向流的RPC时,会返回ClientReaderWriter,:

前面说明了Reader和Writer读取和发送完成的函数调用。因为RPC都是Client请求而后Server响应,双向流也是要Client先发送完自己流,才有Server才可能结束RPC。所以对于双向流的结束过程是:

示例中创建了单独的一个线程去发送请求流,在主线程中读返回流,实现了一定程度上的并发。

3.流是会结束的

并不似长连接,建立上之后就一直保持,有消息的时候发送。(是否有通过建立一个流RPC建立推送机制?)

Server并没有像Client一样调用WriteDone(),而是在消息之后,将statuscode、可选的statusmessage、可选的trailingmetadata追加进行发送,这就意味着流结束了。

本节通过介绍gRPC协议文档描述和对helloworld的抓包,来说明gRPC到底是如何传输的。

1.ABNF语法

2.请求协议

*表示element会重复多次(最少0次)。知道这个就能理解概况里的描述了:

这表示Request是由3部分组成,首先是Request-Headers,接下来是可能多次出现的Length-Prefixed-Message,最后以一个EOS结尾(EOS表示End-Of-Stream)。

2.1Request-Headers

根据上边的协议描述,Request-Headers是由一个Call-Definition和若干Custom-Metadata组成。

[]表示最多出现一次,比如Call-Definition有很多组成部分,其中Message-Type等是选填的:

通过Wireshark抓包可以看到请求的Call-Definition中共有所有要求的Header,还有额外可选的,比如user-agent:

因为helloworld的示例比较简单,请求中没有填写自定义的元数据(Custom-Metadata)

2.2Length-Prefixed-Message

传输的Length-Prefixed-Message也分为三部分:

同样的,Wireshark抓到的请求中也有这部分信息,并且设置.proto文件的搜索路径之后可以自动解析PB:

其中第一个红框(Compressed-Flag)表示不进行压缩,第二个红框(Message-Length)表示消息长度为7,蓝色反选部分则是Protobuf序列化的二进制内容,也就是Message。

这里Length-Prefixed-Message中传输的可以是PB也可以是JSON,须通过Content-Type头中描述告知。

2.3EOS

End-Of-Stream并没有单独的数据去描述,而是通过HTTP2的数据帧上带一个END_STREAM的flag来标识的。比如helloworld中请求的数据帧,也携带了END_STREAM的标签:

3.返回协议

()表示括号中的内容作为单个元素对待,/表示前后两个元素可选其一。Response的定义说明,可以有两种返回形式,一种是消息头、消息体、Trailer,另外一种是只带Trailer:

这里需要区分gRPC的Status和HTTP的Status两种状态。

不管是哪种形式,最后一部分都是Trailers,其中包含了gRPC的状态码、状态信息和额外的自定义元数据。

同样地,使用END_STREAM的flag标识最后Trailer的结束。

4.与HTTP/2的关系

ThelibrariesinthisrepositoryprovideaconcreteimplemnetationofthegRPCprotocol,layeredoverHTTP/2.

gRPC支持上下文的传递,其主要用途有:

客户端添加自定义的metadatakey-value对没有特别的区分,而服务端添加的,则有inital和trailing两种metadata的区分。这也分别对应这ClientContext只有一个添加Metadata的函数:

而ServerContext则有两个:

还有一种CallbackServer对应的上下文叫做CallbackServerContext,它与ServerContext继承自同一个基类,功能基本上相同。区别在于:

1.Stub

.proto中的一个service只有一个Stub,该类中会提供对应每个RPC所有的同步、异步、回调等方式的函数都包含在该类中,而该类继承自接口类StubInterface。

为什么需要一个StubInterface来让Stub继承,而不是直接产生Stub?别的复杂的proto会有多个Stub继承同一个StubInterface的情况?不会,因为每个RPC对应的函数名是不同。

Greeter中唯一一个函数是用于创建Stub的静态函数NewStub:

Stub中同步、异步方式的函数是直接作为Stub的成员函数提供,比如针对一元调用:

回调方式的RPC调用是通过一个experimental_async的类进行了封装(有个async_stub_的成员变量),所以回调Client中提到,回调的调用方式用法是stub_->async()->SayHello(...)。

experimental_async类定义中将Stub类作为自己的友元,自己的成员可以被Stub直接访问,而在StubInterface中也对应有一个experimental_async_interface的接口类,规定了要实现哪些接口。

2.Service

有几个概念都叫Service:proto文件中RPC的集合、proto文件中service产生源文件中的Greeter::Service类、gRPC框架中的::grpc::Service类。本小节说的Service就是helloworld.grpc.pb.h中的Greeter::Service。

2.1Service是如何定义的

helloworld.grpc.pb.h文件中共定义了7种Service,拿出最常用的Service和AsyncService两个定义来说明下Service的定义过程:通过类模板链式继承。

Service跟其他几种Service不同,直接继承自grpc::Service,而其他的Service都是由类模板构造出来的,而且使用类模板进行嵌套,最基础的类就是这里的Service。

Service有以下特点:

所以Service类中的所有RPCAPI都是同步的。

再看AsyncService的具体定义:

所以AsyncService的含义就是继承自Service,加上了WithAsyncMethod_SayHello的新功能:

通过gRPC提供的route_guide.proto例子能更明显的理解这点:

这里RouteGuide服务中有4个RPC,GetFeature、ListFeatures、RecordRoute、RouteChat,通过4个WithAsyncMethod_{RPC_name}的类模板嵌套,能将4个API都设置成ApiType::ASYNC、添加上对应的RequestXXX()函数、禁用同步函数。

2.2Service的种类

helloworld.grpc.pb.h文件中7种Service中,有3对Service的真正含义都相同(出于什么目的使用不同的名称?),实际只剩下4种Service。前三种在前边的同步、异步、回调Server的介绍中都有涉及。

其实这些不同类型的Service是跟前边提到的api_type_有关。使用不同的::grpc::Service::MarkMethodXXX设置不同的ApiType会产生不同的API模板类,所有API模板类级联起来,就得到了不同的Service。这三者的关系简单列举如下:

另外还有两种模板是通过设置其他属性产生的,这里暂时不做介绍:

3.与::grpc核心库的关系

Stub类中主要是用到gRPCChannel和不同类型RPC对应的方法实现

Service类则继承自::grpc::Service具备其父类的能力,需要自己实现一些RPC方法具体的处理逻辑。其它Service涉及到gRPC核心库的联系有:

AsyncService::RequestSayHello()调用::grpc::Service::RequestAsyncUnary。

CallbackService::SayHello()函数返回的是::grpc::ServerUnaryReactor指针。

CallbackService::SetMessageAllocatorFor_SayHello()函数中调用

::grpc::internal::CallbackUnaryHandler::SetMessageAllocator()函数设置RPC方法的回调的消息分配器。

THE END
1.CodeServer是什么?1、什么是 codeserver? code server是coder公司基于微软开源的Visual Studio Code开发的一款产品。 2、code server 的目标是什么? code server 的目标是为开发者构建一个便捷统一的开发环境,让开发者能从任意设备、任意位置通过浏览器来进行代码的编写。从而免去了常规的 IDE 开发流程中的环境搭建的问题。 https://blog.csdn.net/qq_40442753/article/details/113410091
2.codeserver在浏览器里玩转VSCodecodecode-server 是一个轻量级的 Web 应用程序,它允许你在浏览器中运行 Visual Studio Code。它基于 VSCode,但通过一个名为 code-server 的程序在服务器端运行,从而可以在任何可以访问 Web 的设备上使用 VSCode 的功能。 特点 浏览器访问:无需在本地安装任何东西,只需一个现代浏览器即可访问完整的 VSCode 功能集。https://juejin.cn/post/7424906244244946998
3.codeserver配置codeserver部署Code-server是由Coder基于VS Code开发的在线编辑器,通俗来讲,就是把VS Code搬到了浏览器上,Code-Server作为Web IDE的存在,可以实现随时随地的写代码。 code-server的优势 随时随地编写代码:使用一致的开发环境,在多种设备上设置代码,然后通过Web浏览器从任何设备中获取 https://blog.51cto.com/u_16213653/10739826
4.codeserver安装部署,平板手机随时随地写代码sudo systemctl status code-server # 查看服务状态 配置成功后,重启服务器即可自行启动 code-server 服务并在后台运行。 使用 配置完成后,在浏览器输入 <IP>:8080 可直接访问 code-server,使用刚设定好的密码登录。同本地 VS Code 一样可下载插件进行配置。 https://www.jianshu.com/p/a3fcdc434084
5.搭建codeserver实现随时随地coding天翼云开发者社区coder.com 提供了一个在浏览器里面"运行"vscode的一个开源方案--code-server,本文将介绍如何使用code-server搭建开发环境实现随时随地进行编码。 环境准备 为了部署code-server应用,需要在购买如下云上资源: 下载code-server code-server在github上开源,下载最新的发行版本 github.com/coder/code-server/releases https://www.ctyun.cn/developer/article/469108934066245
6.code但是其属于一款客户端软件,在远程服务器上使用不如 code-server,code-server 是一款能够在网页上使用的 vscode,极大的方便程序开发人员快速访问与编码。本篇介绍如何在 ubuntu 18.04 上安装和配置,使其适用于 python 开发。 安装 bash 1 2 3 4 5 6https://xujinzh.github.io/2024/04/10/install-code-server/
7.codeserver:codecurl -fsSL https://code-server.dev/install.sh | sh When done, the install script prints out instructions for running and starting code-server. Note To manage code-server for a team on your infrastructure, see: coder/coder We also have an in-depth setup and configuration guide. Questionshttps://gitee.com/mirrors/code-server/
8.Codeserver搭建webIDE詩GIthub官方文档:https://github.com/cdr/code-server 原理基础 code-server是一款基于VScode的在线编辑器,主要用于在Linux服务器环境下,实现任何设备通过浏览器即可访问VScode, 进而实现在远程编程. 下载资源 https://github.com/cdr/code-server 该链接进入后,直接选择release下载最新版本的code-server. https://www.cnblogs.com/billyme/p/13769847.html
9.codeserver详细安装code-server2.1650-vsc1.39.2-linux-x86_64.tar.gz。下载完成之后解压即可: 2、运行 输入指令./code-server--help,即可查看相关指令:直接输入指令./code-server即可启动codeserver: 这里监听的前言 因项目需要,需要一个在线的ide,用来查看、修改、部署代码,几番搜索、对比之后选择code-server这个在线ide,其githhttps://www.pianshen.com/article/49381619342/
10.WSL2下手动安装vscodeserver很简单,就是把刚才的vscode-server-linux-x64目录,改名字,移动到.vscode-server/bin/目录里去。 $ cd ~ $ mv vscode-server-linux-x64 .vscode-server/bin/f1a4fb101478ce6ec82fe9627c43efbf9e98c813 这就完成了,再code .就可以脸上windows的vs code了。http://lvkedu.com/detail/94/
11.org.springframework.http.codec.ServerCodecConfigurer这个包的publicvoidconfigureHttpMessageCodecs(ServerCodecConfigurerconfigurer){ // 注册Jackson JSON编解码器 ObjectMappermapper=newObjectMapper(); mapper.setDateFormat(newSimpleDateFormat("yyyy-MM-dd")); configurer.defaultCodecs().jackson2JsonEncoder(newJackson2JsonEncoder(mapper)); https://avmedia.0voice.com/?id=41190
12.codehttps://github.com/cdr/code-server/releases 二、解压后,获得一个绿色的执行文件code-server,执行后,立即可以从远端访问code-server [root@VM_0_4_centos codeserver]# ./code-server info Server listening on http://localhost:8080 info - Password is 62bc2c14156d24e45e60cd92 http://blog.coolcoding.cn/?p=1269
13.SecurityOAuth2Demo——授权码模式(AuthorizationCode.authorizedGrantTypes("authorization_code") //授权模式标识 .scopes("read_user_info") //作用域 .resourceIds("resource1") //资源id .redirectUris("http://localhost:9001/callback"); //回调地址 // @formatter: on } } 1.通过@Configuration 和EnableAuthorizationServer开启授权服务器配置,通过重写Authhttps://maimai.cn/article/detail?fid=1796603548&efid=xkUVVnyJ-EF0nQATO8TK-w
14.codeserveradministratorguide快速入门wecode-server是社区创作的 Web 版 VS Code,后端运行在服务器中,开发者基于浏览器运行 IDE。 部署Websoft9 提供的 code-server 之后,请参考下面的步骤快速入门。 准备? 在云控制台获取您的服务器公网IP地址 在云控制台安全组中,确保Inbound(入)规则下的TCP:80端口已经开启 https://support.websoft9.com/docs/codeserver
15.Helpercode:ServerConnectionclassMicrosoftLearnThe credential naming format is Microsoft_CRMSDK:<server>:<organization>:<userID>.Useful code for authentication can be found in the GetProxy and GetOrganizationProxy methods. Also, the code that creates and reads a user’s password in the Windows Credential Manager may be of interest.https://msdn.microsoft.com/en-us/library/gg309393.aspx
16.使用coderserver打造在线IDE腾讯云开发者社区具体部署可以参考官方文档:https://coder.com/docs/code-server/latest/install。 这里我们选择相对简单快捷的方式,Docker部署。 前置条件 在部署coder-server前,你需要准备一台Linux虚机(建议CentOS7),你可以去云厂商购买(用于生产),也可以使用VMware在个人电脑创建虚机(用于学习)。 https://cloud.tencent.com/developer/article/2025560
17.VSCodeWebIDECoder安装及使用其它综合以golang为例,安装go插件,但是没有什么卵用 如果是用的code-server docker容器,在“~/project/go/go/”下已经有了go的安装文件,只是要添加到环境变量 1 export PATH=$PATH:~/project/go/go/bin 打开终端,运行go run main.go,可以看到效果 到此这篇关于VSCode Web IDE Coder 安装及使用的文章就介绍到这https://www.jb51.net/article/231012.htm
18.我要自学网AppiumAPP开发AuthorwareCC#C++JAVALoadRunnerMySQLOraclePythonScratchSeleniumSQL SERVERUE4Unity3D编程入门数据库易语言游戏开发 更多 Python程序设计教程(2024版) JAVA语言入门教程2022版 Oracle数据库入门教程 Python爬虫教程 AccessASPASP.NETC#canvasCSSDreamweaverFlashHTMLJavaScriptjQueryLinuxPHPvueWindows后台开发前端设计淘宝http://51zxw.net/
19.解决VSCode自动更新版本后卡在连接界面晚花行乐如果不想每次自动更新后都手动执行一次脚本,那么可以关闭 VS Code 的自动更新。 打开Setting, 搜索update关键字,按照图中红框里的选项配置即可。 如果您对本文有疑问或者寻求合作,欢迎联系邮箱。邮箱已到剪贴板 给个免费的赞吧~ 0 ? 前一篇: 在 Windows 10 LTSC 版本上安装 WSL2 https://www.lfhacks.com/tech/vscode-server/
20.MaxCompute操作报错合集之遇到报错信息"SERVERINTERNAL请问大数据计算MaxCompute:使用网关API服务的时候,调用这张表报错ERROR: status { code: SERVER_INTERNAL_ERROR message: \"query next from foreign table executor failed, ORC with cid cannot be opened w/o cid list! } 是因为没有权限吗? 参考回答: https://developer.aliyun.com/article/1545306
21.使用技巧机器纬度:~/.local/share/code-server/Machine/settings.json 仓库维度:.vscode/settings.json。相对目录为当前工作区(默认为/var/run/workspace) VSCode 客户端(remote-ssh) 的配置文件(settings.json)路径如下: 用户维度:~/.vscode-server/data/User/settings.json https://coding.net/help/docs/cnb/remote-dev/tips.html