目录

  • 1. 引言
  • 2. 定义gRPC服务
  • 3. 抓包Unary方法
  • 3.1 gRPC请求解析
  • 3.2 gRPC响应解析
  • 4. 抓包Bidirectional Stream方法


1. 引言

平时我们在浏览器中(如Chrome)可以通过开发者工具中的Network非常方便的查看HTTP/1.1和HTTP/2协议,

比如可以查询HTTP请求的protocol、host、method、path、headers、payload及response信息等相关数据,非常直观。

go语言抓包伪装 grpc 抓包_grpc

gRPC协议也是构建在HTTP/2上,并使用protobuf序列化通信数据,
我们可以通过Wireshark工具对gRPC通信进行抓包, 以查看其是如何运转在HTTP/2协议之上的,并且和我们平时的HTTP协议有何区别。

注: 使用WireShark抓取gRPC协议需要一些特殊设置, 具体设置可参见我之前的文章:《wireshark支持gRPC协议》

2. 定义gRPC服务

测试抓包使用的gRPC服务定义可参见我之前的一篇文章《gRPC Java入门示例》的Hello服务定义。

/*
* HelloWorld入门示例
*/

//使用proto3语法
syntax = "proto3";

//proto包名
package hello;
//生成多个Java文件
option java_multiple_files = true;
//指定Java包名
option java_package = "com.luo.demo.grpc.hello";
//指定Java输出类名
option java_outer_classname = "HelloProto";



//gRPC服务定义
service Hello {
  //gRPC服务方法定义 - Unary
  rpc sayHello (HelloRequest) returns (HelloReply) {}

  //gRPC服务方法定义 - Server Streaming - 服务端流
  rpc sayHelloServerStream (HelloRequest) returns (stream HelloReply) {}

  //gRPC服务方法定义 - Client Streaming - 客户端流
  rpc sayHelloClientStream (stream HelloRequest) returns (HelloReply) {}

  //gRPC服务方法定义 - BiDirection Streaming - 双向流
  rpc sayHelloBiStream (stream HelloRequest) returns (stream HelloReply) {}
}

//请求参数定义
message HelloRequest {
  string name = 1;
}

//响应结果定义
message HelloReply {
  string message = 1;
}

如上proto定义了Hello服务的4个方法,分别对应不同的类型:

包名package

服务名

方法名

方法类型

hello

Hello

sayHello

Unary

hello

Hello

sayHelloServerStream

Server Streaming

hello

Hello

sayHelloClientStream

Client Streaming

hello

Hello

sayHelloBiStream

BiDirection Streaming

入门抓包使用Unary方法sayHello,
进阶使用Bidirectional Stream方法sayHelloBiStream。

注:
由于Bidirecitional Stream是Client Stream和Server Stream的超集,
故不在对sayHelloClientStream和sayHelloServerStream进行抓包演示,
具体细节可参见sayHelloBiStream。

3. 抓包Unary方法

启动gRPC Server端和Client端,发起一次sayHello请求,使用Wireshark抓包后一个完整的请求如下图:

go语言抓包伪装 grpc 抓包_go语言抓包伪装_02

这里直接讲解此次gRPC通信的几个重点步骤:

  • #6444 gRPC请求
  • #6458 gRPC响应头
  • #6467 gRPC响应数据

3.1 gRPC请求解析

查看#6444 gRPC请求对应的协议解析详情,如下图:

go语言抓包伪装 grpc 抓包_wireshark_03


如上图可以发现HTTP2请求对应到gRPC请求,关系如下:

HTTP2协议

GRPC协议

:authority

Server端地址

:method

POST

:path

/{package}.{service}/{method}

/包名.服务名/方法名

  • /hello.Hello/sayHello
  • /hello.Hello/sayHelloServerStream
  • /hello.Hello/sayHelloClientStream
  • /hello.Hello/sayHelloBiStream

content-type

application/grpc

grpc-accept-encoding

gzip

DATA(payload OR 请求数据)

Protobuf message定义的参数,

hello.HelloRequest

3.2 gRPC响应解析

查看#6458 gRPC响应头对应的协议解析详情,如下图:

go语言抓包伪装 grpc 抓包_http2_04


查看#6467 gRPC响应数据对应的协议解析详情,如下图:

go语言抓包伪装 grpc 抓包_http2_05


如上图可以发现HTTP2响应对应到gRPC响应,关系如下:

HTTP2协议

GRPC协议

:status

HTTP响应码

grpc-status

grpc响应码

content-type

application/grpc

grpc-accept-encoding

gzip

grpc-encoding

identity

DATA(响应数据 )

Protobuf message定义的返回结果),

hello.HelloReply

4. 抓包Bidirectional Stream方法

发起一次sayHelloBIStream调用,示例代码中Client端发送了3次请求,相应的Server端也回应了3次,

注:
实际测试时发现,若Client端连续发送多次请求且间隔较短,Client端会合并多次请求为1次,但Server端还是分多次返回。
故在此次测试中将Client端2次发送间添加了2~3秒间隔,以便更直观展示抓取效果。

使用Wireshark抓包后效果如下图:

go语言抓包伪装 grpc 抓包_http2_06

可以发现一共发送了3次gRPC双向通信且使用同一个连接(同一个tcp.stream=23),
每一次的gRPC请求及返回与之前的Unary调用类似,故不在展开,
需要注意的是仅第一次gRPC通信发送了请求HEADERS和响应HEADERS,后续的请求都不在发送相关HEADERS。


参考:
https://imququ.com/post/header-compression-in-http2.html

https://grpc.github.io/grpc/core/md_doc_statuscodes.html

https://pingcap.com/zh/blog/grpc