在使用gRpc的过程中,有一个想法:gRpc客户端和服务端是如何交互的?以此思路推导出验证方法,通过抓包分析交互过程。让我们看一下底层数据。1.什么是gRpc什么是gRpc?gRPC是一种高性能、开源和通用的RPC框架,专为移动和HTTP/2而设计。目前有C、Java和Go语言版本,分别为:grpc、grpc-java、grpc-go。C版本支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#。gRPC是基于HTTP/2标准设计的,在单个TCP连接上带来了双向流、流量控制、头部压缩和多路复用请求等特性。这些特性使其在移动设备上表现更好,节省电力和空间。一句话概括:gRpc是Google开源的一款基于HTTP/2+ProtoBuf的RPC框架。2、准备工作俗话说:工欲善其事必先利其器,所以在开始抓包之前需要做好以下准备工作:抓包软件:wireshark代码:gRpc代码操作系统:Windows、Linux、Macos13.Wireshark安装官网下载地址:https://www.wireshark.org/download.htmlwireshark4。gRpc示例代码示例代码目录结构。└──helloworld├──client│└──main.go├──go.mod├──go.sum├──proto│├──helloworld.pb.go│└──helloworld.proto└──server└──main.gohelloworld.protosyntax="proto3";packageproto;//greetingservicedefinition.serviceGreeter{//SendsagreetingrpcSayHello(HelloRequest)returns(HelloReply){}}//Therequestmessagecontainingtheuser'sname.messageHelloRequest{stringname=1;int32age=2;}//TheresponsemessagecontainingthegreetingsmessageHelloReply{stringmessage=1;stringaddress=2;}通过protoc代码生成proto文件cdprotoprotoc--go_out=plugins=grpc:../*servercode-server/main.gopackagemainimport("context""log""net"pb"github.com/ivansli/grpc_helloworld/proto""google.golang.org/grpc")const(port=":8080")//serverisusedtoimplementhelloworld.GreeterServer.typeserverstruct{}//SayHelloimplementshelloworld.GreeterServerfunc(s*server)SayHello(ctxcontext.Context,in*pb.HelloRequest)(*pb.HelloReply,error){log.Printf("Received:%v",in.GetName())return&pb.HelloReply{Message:"Hello"+in.GetName()},nil}funcmain(){lis,err:=net.Listen("tcp",port)iferr!=nil{log.Fatalf("failedtolisten:%v",err)}s:=grpc.NewServer()pb.RegisterGreeterServer(s,&server{})log.Printf("serverlisteningat%v",lis.Addr())iferr:=s.Serve(lis);err!=nil{log.Fatalf("failedtoserve:%v",err)}}客户端代码-client/main.gopackagemainimport("context""google.golang.org/grpc/metadata""log""os""time"pb"github.com/ivansli/grpc_helloworld/proto""google.golang.org/grpc")const(address="localhost:8080"defaultName="world")funcmain(){//设置服务器连接。conn,err:=grpc.Dial(地址,grpc.WithInsecure())iferr!=nil{log.Fatalf("didnotconnect:%v",err)}deferconn.Close()c:=pb.NewGreeterClient(conn)//Contacttheserverandprintoutitsresponse.name:=defaultNameiflen(os.Args)>1{name=os.Args[1]}ctx,cancel:=context.WithTimeout(context.Background(),time.Second)defercancel()//!Metadata是用来在服务之间传递一些参数,注意后面在交互中出现在哪里{Name:name})iferr!=nil{log.Fatalf("couldnotgreet:%v",err)}log.Printf("Greeting:%s",r.GetMessage())}5.步骤①运行服务器代码server/main.go,监听8080端口gorunserver/main.go②打开wireshark等待抓包③运行客户端代码client/main.gogorunclient/main.go6。Wireshark抓包gRpc交互过程Wireshark抓包gRpc交互过程仔细观察Protocol栏中的协议类型:TCP传输层HTTP2应用层GRPC应用层(基于HTTP/2)GRPC和HTTPS/2的区别在于GRPCprotocol包含ProtoBuf序列化数据,这也间接证实了GRPC=HTTP/2+ProtoBuf通过抓包我们发现客户端使用53726端口与监听8080的服务器进行交互并传输数据。流程大致分为10①TCP三向握手②Magic③SETTINGS④HEADERS⑤DATA⑥WINDOW_UPDATE,PING⑦PING(pong)⑧HEADERS,DATA⑨WINDOW_UPDATE,PING⑩PING(pong)。标头、数据、WINDOW_UPDATE、PING。至于它们的作用,我们看下面的分析:MagicmagicframeMagicframe的主要作用是确认双方使用HTTP/2的协议,它是一个链接序言。作用是判断是否开启HTTP/2连接。SETTINGSSETTINGS的主要作用是设置本次连接的参数,作用于整个连接。从图中可以看出有多个SETTINGS,原因是连接前导码发送后,客户端和服务端还需要进一步确定一些信息。客户端发送给服务器的SETTINGS服务器发送给客户端的SETTINGSHEADERSHEADERS的主要作用是存储和传输HTTP头信息。客户端发送给服务端的HEADERS可以看到很多重要的信息:methodschemepathauthoritycontent-typeuser-agent等,这些都是gRpc非常重要的基础属性。注意:使用google.golang.org/grpc/metadata包元数据在客户端和服务端之间传输数据,仔细观察HEADERS中服务端发送给客户端的HEADERS。服务端发送给客户端的HEADERS帧中的HEADERS数据分为HTTP响应状态和内容两部分(第一个Stream:HEADERS)status:200content-type:application/grpc携带的状态信息通过gRpc(第二个Stream:HEADERS,图中框起来的部分)grpc-status:0grpc-message:DATADATA的主要作用是填充主体信息,是一个数据框。客户端发送给服务端的DATA包括两个重要的部分:①GRPCMessage/proto.Greeter/SayHello是服务在proto中定义的方法,也是服务端提供的方法。②ProtocolBuffers与protobuf相关,其中Field(1)是定义的pb.HelloRequest结构中的Name参数&pb.HelloRequest{Name:"world"}。注意:①pb.HelloRequest{}结构体中age字段为零值,在传输过程中被忽略,所以没有Field(2)②带有request标志,表示这是客户端发起的请求,并且服务器发送给客户端的DATA类似于客户端发送给服务器的DATA,其中Field(1)是&pb.HelloReply{Message:"Helloworld"}的Message字段。注意:①pb.HelloReply{}结构体中的地址字段为零值,在传输过程中被忽略,所以没有Field(2)②它有一个响应标志,表示这是一个响应消息WINDOW_UPDATE的主要功能WINDOW_UPDATE是管理流控窗口。客户端发送给服务器的WINDOW_UPDATE服务器发送给客户端的WINDOW_UPDATEPING主要用于判断当前连接是否还可用,相当于一次心跳。分为:客户端ping服务器,服务器pong服务器ping客户端,客户端pong服务器发给客户端的PING和客户端响应服务器发来的PONG。注意:同一个Ping/Pong具有相同的标识字符串(图中标识为:02041010090e0707)。综上所述,我们通过捕获gRpc的交互过程来分析不同类型框架的作用,进一步了解gRpc。总结如下:gRpc的三次握手后,client/server会发送connectionpreamble(Magic+SETTINGS)建立协议,配置gRpc。在数据传输过程中,gRpc会设计滑动窗口(WINDOW_UPDATE)等流控策略,gRpc的附加信息是根据HEADERS帧传输的,具体的请求/响应数据存放在DATA帧中。gRpc请求/响应结果分为两种:HTTP和gRpc状态响应(grpc-status,grpc-message)。如果服务器发起PING,客户端将响应PONG,反之亦然
