欢迎地鼠同胞!很多人要求我写一篇关于gRPC主题的教程,以及如何在Go中编写自己的基于gRPC的系统。因此,在本教程中,我们将深入了解gRPC精彩而令人兴奋的世界,并探索我们如何利用它来获得名利! 我们将深入研究gRPC背后的理论,以及为什么与HTTPRESTAPI等更传统的设置相比,它在某些情况下会更好。 一旦我们掌握了gRPC如何使我们的系统受益的问题,我们将看看如何构建用Go编写的简单gRPC客户端和服务器! 先决条件 在完成本教程之前,您必须在您的机器上安装以下内容:已安装ProtocolBuffersv3这可以通过运行来完成gogetugithub。comgolangprotobufprotocgengo 您必须确保它GOPATHbin位于您的环境路径中,以便您可以protoc在本教程后面使用该工具。gRPC简介 因此,在深入研究之前,我们首先需要了解gRPC是什么,它是如何工作的等等。 定义gRPC是一个现代的、开源的远程过程调用(RPC)框架,可以在任何地方运行 远程过程调用是我们在分布式系统中使用的东西,它允许我们在应用程序之间进行通信。更具体地说,它允许我们在我们的应用程序中公开我们希望其他应用程序能够调用的方法。 它类似于RESTAPI通信,通过它,您可以有效地将应用程序中的功能公开给使用HTTP连接作为通信媒介的其他应用程序。gRPC和REST的区别 虽然REST和gRPC有点相似,但您应该注意它们的工作方式存在一些根本差异。gRPC利用HTTP2而REST利用HTTP1。1gRPC使用协议缓冲区数据格式,而不是通常在RESTAPI中使用的标准JSON数据格式使用gRPC,您可以根据需要利用HTTP2服务器端流式传输、客户端流式传输甚至双向流式传输等功能。gRPC的挑战 您应该记住,虽然gRPC确实允许您利用这些更新的技术,但由于无法使用PostmanHTTP客户端等工具来轻松与暴露的gRPC交互,因此对gRPC服务进行原型设计更具挑战性服务。 您确实有使这成为可能的选项,但这并不是本机即可获得的。有一些选项可以使用诸如envoy之类的工具来反向代理标准JSON请求并将它们转码为正确的数据格式,但这是一个额外的依赖项,对于简单项目的设置可能会很棘手。在Go中构建gRPC服务器 让我们从在Go中定义一个非常简单的gRPC服务器开始。一旦我们有一个简单的服务器启动并运行,我们就可以着手创建一个能够与之交互的gRPC客户端。 我们将首先在main函数中编写逻辑来侦听传入TCP连接的端口: main。gopackagemainimport(lognet)funcmain(){lis,err:net。Listen(tcp,:9000)iferr!nil{log。Fatalf(failedtolisten:v,err)}} 接下来,我们gRPC要从中导入官方包,golang。org以便我们可以创建一个新的gRPC服务器,然后在通过我们TCP上面定义的现有连接提供服务之前注册我们想要公开的端点: main。gopackagemainimport(lognetgoogle。golang。orggrpc)funcmain(){lis,err:net。Listen(tcp,:9000)iferr!nil{log。Fatalf(failedtolisten:v,err)}grpcServer:grpc。NewServer()iferr:grpcServer。Serve(lis);err!nil{log。Fatalf(failedtoserve:s,err)}} 这是用go编写的gRPC服务器的绝对最低要求。但是,现在它并没有做太多。添加一些功能 让我们看看我们如何开始通过我们的gRPC服务器公开一些功能,以便gRCP客户端可以以有意义的方式与我们的服务器交互。 让我们首先定义chat。proto将作为我们的合约的文件: 聊天。protosyntaxproto3;packagechat;messageMessage{stringbody1;}serviceChatService{rpcSayHello(Message)returns(Message){}} 该。proto文件公开了我们的ChatService其中一个SayHello功能,该功能可以由任何用任何语言编写的gRPC客户端调用。 这些。proto定义通常在各种形状和大小的客户端之间共享,以便它们可以生成自己的代码来与我们的gRPC服务器通信。 让我们使用该protoc工具生成Go特定的gRPC代码:protocgooutpluginsgrpc:chatchat。proto 您会看到这将生成一个chatchat。pb。go包含生成代码的文件,以便我们在代码中轻松调用。让我们更新我们的server。go以注册我们的ChatService,如下所示: 服务器。gopackagemainimport(fmtlognetgithub。comtutorialedgegogrpcbeginnerstutorialchatgoogle。golang。orggrpc)funcmain(){fmt。Println(GogRPCBeginnersTutorial!)lis,err:net。Listen(tcp,fmt。Sprintf(:d,9000))iferr!nil{log。Fatalf(failedtolisten:v,err)}s:chat。Server{}grpcServer:grpc。NewServer()chat。RegisterChatServiceServer(grpcServer,s)iferr:grpcServer。Serve(lis);err!nil{log。Fatalf(failedtoserve:s,err)}} 然后我们将不得不定义SayHello接收a的方法Message,读取消息的正文,然后返回Message它自己的a: 聊天chat。gopackagechatimport(loggolang。orgxnetcontext)typeServerstruct{}func(sServer)SayHello(ctxcontext。Context,inMessage)(Message,error){log。Printf(Receivemessagebodyfromclient:s,in。Body)returnMessage{Body:HelloFromtheServer!},nil} 如果我们想为我们的gRPC服务器定义更高级的功能,那么我们可以通过定义一个从我们的服务器构建的新方法struct,然后将该函数的名称添加到我们的chat。proto文件中,以便我们的应用程序可以将其公开为其他gRPC客户端的东西可以打。 完成这些最终更改后,让我们尝试运行我们的服务器:gorunserver。goGogRPCBeginnersTutorial! 惊人的!我们现在localhost:9000在我们的机器上启动并运行了一个全新的、闪亮的新gRPC服务器!在Go中构建gRPC客户端 现在我们的服务器已经启动并运行了,让我们看看如何构建一个能够与之交互的简单客户端。 客户端。gopackagemainimport(loggolang。orgxnetcontextgoogle。golang。orggrpcgithub。comtutorialedgegogrpcbeginnerstutorialchat)funcmain(){varconngrpc。ClientConnconn,err:grpc。Dial(:9000,grpc。WithInsecure())iferr!nil{log。Fatalf(didnotconnect:s,err)}deferconn。Close()c:chat。NewChatServiceClient(conn)response,err:c。SayHello(context。Background(),chat。Message{Body:HelloFromClient!})iferr!nil{log。Fatalf(ErrorwhencallingSayHello:s,err)}log。Printf(Responsefromserver:s,response。Body)} 当我们运行它时,我们应该看到我们的客户端Hello从服务器收到了一个非常好的消息,如下所示:gorunclient。go2020043020:10:09Responsefromserver:HelloFromtheServer! 太棒了,我们已经成功创建了一个非常简单的gRPC客户端,它现在可以与我们的新gRPC服务器通信了!挑战 挑战添加一个新方法调用BroadcastMessage到我们的gRPC服务器。 挑战剧透 首先修改chat。proto包含gRPC合约的文件。您将新rpc定义添加到您ChatService的名称中BroadcastMessage:syntaxproto3;packagechat;messageMessage{stringbody1;}serviceChatService{rpcSayHello(Message)returns(Message){}rpcBroadcastMessage(Message)returns(Message){}} 有了这个,你就想chat。pb。go从这个更新的合同中重新生成你的文件:protocgooutpluginsgrpc:chatchat。proto 然后您必须将此方法定义添加到您的chatchat。go文件中:packagechatimport(loggolang。orgxnetcontext)typeServerstruct{}func(sServer)SayHello(ctxcontext。Context,inMessage)(Message,error){log。Printf(Receivemessagebodyfromclient:s,in。Body)returnMessage{Body:HelloFromtheServer!},nil}func(sServer)BroadcastMessage(ctxcontext。Context,inMessage)(Message,error){log。Printf(Broadcastingnewmessagefromaclient:s,in。Body)returnMessage{Body:Broadcastedmessage!},nil} 最后,您可以更新client。go代码以调用这个新的gRPC端点:packagemainimport(loggolang。orgxnetcontextgoogle。golang。orggrpcgithub。comtutorialedgegogrpcbeginnerstutorialchat)funcmain(){varconngrpc。ClientConnconn,err:grpc。Dial(:9000,grpc。WithInsecure())iferr!nil{log。Fatalf(didnotconnect:s,err)}deferconn。Close()c:chat。NewChatServiceClient(conn)response,err:c。SayHello(context。Background(),chat。Message{Body:HelloFromClient!})iferr!nil{log。Fatalf(ErrorwhencallingSayHello:s,err)}log。Printf(Responsefromserver:s,response。Body)response,errc。BroadcastMessage(context。Background(),chat。Message{Body:MessagetoBroadcast!})iferr!nil{log。Fatalf(ErrorwhencallingBroadcastMessage:s,err)}log。Printf(Responsefromserver:s,response。Body)} 惊人的!您已成功添加新的gRPC端点!结论 因此,在本教程中,我们研究了如何在Go中构建一个简单的gRPC客户端和服务器。我们构建了一个基本服务器,它接受来自客户端的传入消息,然后向这些客户端返回响应。 现在,这只是我深入研究gRPC的开始,在接下来的几周内,我们将扩展本文中提出的基础,我们将研究更复杂的主题,例如身份验证和授权以及双路流媒体!