最近因为GRPC协议兼容问题受困,于是做了一些实验来验证其原理
proto文件
syntax = "proto3";
package IRPC;
message REQHEADER
{
uint32 nState=1; //校验位 表面数据类型,为了快速定错。0- 无数据 1- 请求数据
uint32 nByteLen=2; //整个grpc请求或响应数据的总长度
uint32 nCrc=3; //整个grpc请求或响应数据的crc校验---32位crc
uint32 nEnType=4; //内容数据是否使用了加密 0- 无加密1-AES加密 2-SM4加密
uint32 nErrCode=5; //错误码---如果是请求包,则该字段=0 如果是响应数据 则=对应的错误码
uint32 nPort=6; //服务端grpc端口 用来定位问题
string strFunName=7; //函数名称 请求时=请求者的函数名 响应时=服务端的函数名
string strUser=8; //进程名称 请求时=请求者的进程名称 响应时=服务端的进程名称--用来定位问题
string strTime=9; //时间戳 "2021-12-29 09:08:23:332"
string strKey=10; //加密的密钥
string strUuid=11; //每次请求的唯一ID 用于异步回调
}
message REQ
{
bytes adata = 1; //数据
string aa=2;
string ab=3;
string ae=4;
REQHEADER aheader=5;
}
message REP
{
bytes data = 1;//数据
}
service S
{
rpc F (REQ) returns (REP);
}
请求端
std::thread getIdThread([&]()
{
grpc_init();
const auto len = 24 * 1024 * 1024;
ChannelArguments arg;
arg.SetMaxReceiveMessageSize(len);
//arg.SetInt("grpc.max_receive_message_length", len);
std::string addr = "127.0.0.1:8899";
auto chan = grpc::CreateCustomChannel(addr,grpc::InsecureChannelCredentials(),arg);
m_cli = IRPC::S::NewStub(chan);
int index=0;
while( true )
{
ClientContext ctx;
IRPC::REQ req;
req.set_aa("aa");
req.set_ab("ab");
req.set_adata("xxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzzz");
req.set_ae("ae");
IRPC::REQHEADER* pheader = req.mutable_aheader();
pheader->set_nstate(100);
pheader->set_nbytelen(200);
pheader->set_ncrc(300);
pheader->set_nentype(400);
pheader->set_nerrcode(500);
pheader->set_nport(666);
pheader->set_strfunname("strfunname");
pheader->set_struser("struser");
pheader->set_strtime("strtime");
pheader->set_strkey("strkey");
pheader->set_struuid("struuid");
IRPC::REP rep;
Status s = m_cli->F(&ctx,req,&rep);
if( !s.ok() )
{
std::cout<<"errmsg="<<s.error_message()<<endl;
grpc::StatusCode e = s.error_code();
std::cout<<"errcode="<<e<<endl;
}
int ns=req.ByteSizeLong();
std::cout<<"send len="<<ns<<endl;
std::cout<<"idx="<<index++<<endl;
usleep(1000);
}
});
getIdThread.detach();
服务端
.class CServ:public IRPC::S::Service
{
public:
CServ(){}
~CServ(){}
Status F(grpc::ServerContext *context, const IRPC::REQ *request, IRPC::REP *response) override;
};
Status CServ::F(grpc::ServerContext *ctx, const IRPC::REQ *req, IRPC::REP *rep)
{
return Status::OK;
}
启动服务端
std::thread getIdThread([&]()
{
grpc_init();
m_serv= std::make_shared<CServ>();
ServerBuilder serverBuilder;
const auto maxSize = 24 * 1024 * 1024;
serverBuilder.SetMaxSendMessageSize(maxSize);
serverBuilder.SetMaxReceiveMessageSize(maxSize);
//grpc::SslCredentials(grpc::SslCredentialsOptions());
std::string addr = "0.0.0.0:8899";
serverBuilder.AddListeningPort(addr, grpc::InsecureServerCredentials());
serverBuilder.RegisterService(m_serv.get());
std::unique_ptr<Server> server(serverBuilder.BuildAndStart());
server->Wait();
});
getIdThread.detach();
实验1:请求端与服务端协议乱序
请求端:
message REQ
{
bytes adata = 1; //数据
string aa=2;
string ab=3;
string ae=4;
REQHEADER aheader=5;
}
服务端:
message REQ
{
string aa=1;
string ab=2;
bytes adata = 3;
string ae=4;
REQHEADER aheader=5;
}
结果:请求失败,错误码:StatusCode::UNIMPLEMENTED
实验2:协议对齐-请求协议尾部顺序缺少数据
请求端:
message REQ
{
bytes adata = 1; //数据
string aa=2;
string ab=3;
string ae=4;
}
服务端:
message REQ
{
bytes adata = 1; //数据
string aa=2;
string ab=3;
string ae=4;
REQHEADER aheader=5;
}
结果:请求成功,服务端收到的aheader内容均为0
实验2:协议对齐-请求协议尾部顺序多余数据
请求端:
message REQ
{
bytes adata = 1; //数据
string aa=2;
string ab=3;
string ae=4;
REQHEADER aheader=5;
}
服务端:
message REQ
{
bytes adata = 1; //数据
string aa=2;
string ab=3;
string ae=4;
}
结果:请求成功