gRPC+protobuf通用函数之间远程调用,两点之间只用一个接口,传所有函数

gRPC函数之间远程调用是实现了,但是还是非常的不方便,不够自动化。

1.要写proto文件,应该自动生成

2.还是要封解包参数,每个函数都得做一次。

我想要的是两点之间只用一个接口,传所有函数。

 所有函数封装成发送与接收 :函数名,请求参数,响应参数,返回值

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}


message HelloRequest {
  string methodName = 1; //函数名唯一标识 
  string jsonPara=2; //所有参数封装到json
}


message HelloReply {
  string jsonPara=2; //所有参数封装到json
  string resultCode=3; //返回值
}

client实现 (C++)

int invole(methodName,...)
{
    
}

server实现(java)

java反射得到函数名,与传过来的对比

mapping()
{

}

如果是自己用,上面完成可以实现。

最终采用:gRPC+protobuf+json方案

因为需要提供接口给用户,所以把函数名全给出,只是把参数转为json。

proto内容:函数名,请求jsonPara所有参数,响应jsonPara所有参数,返回值。

syntax = "proto3";
 
option java_multiple_files = true;
option java_package = "io.grpc.pos.remotemethods";
option java_outer_classname = "PosRemoteMethods";
option objc_class_prefix = "PRM";
package pos;
 
service  RemoteMethods{

	rpc LoadSymKey(Request) returns (Reply) {}
	
	rpc GetDeviceInfo(Request) returns (Reply) {}

}
 
 
message Request {
  string jsonPara=1;
}

message Reply {
  string jsonPara=1;
  uint32 resultCode=2;
}

约定:

1.byte数组 都转成十六进制字符串,收发都转。好处理些。但有些长度是指针的,所有长度直接用整型传值。
2.结构体像单独字段一样传。一般不会与其它参数同名。

Server


#include <iostream>
#include <memory>
#include <string>

#include <json.h>
using namespace Json;

#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>


#ifdef BAZEL_BUILD
#include "examples/protos/pos.grpc.pb.h"
#else
#include "pos.grpc.pb.h"
#endif

using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using pos::RemoteMethods;
using pos::Reply;
using pos::Request;

using namespace std;
//将字符串编码成16进制数字,适用于所有字符(包括中文)
std::string encodeHexString(const std::string& str) {
	// 根据默认编码获取字节数组
	const std::string hexString = "0123456789abcdef";
	string sb;
	// 将字节数组中每个字节拆解成2位16进制整数
	for (int i = 0; i < str.length(); i++) {
		sb += hexString.at((str[i] & 0xf0) >> 4);
		sb += hexString.at((str[i] & 0x0f) >> 0);
	}
	return sb;
}
//16进制字符串转字符串
std::string hexStringToString(const std::string& hexStr)
{
	std::string ret;
	const std::string hexString = "0123456789abcdef";
	// 将每2位16进制整数组装成一个字节
	for (int i = 0; i < hexStr.length(); i += 2)
		ret += BYTE(hexString.find(hexStr.at(i)) << 4 | hexString.find(hexStr.at(i + 1)));
	return ret;
}
//字节数组转16进制字符串
std::string bytesToHexString(const BYTE* bytes, const int length)
{
	if (bytes == NULL) {
		return "";
	}
	std::string buff;
	const int len = length;
	for (int j = 0; j < len; j++) {
		int high = bytes[j] / 16, low = bytes[j] % 16;
		buff += (high < 10) ? ('0' + high) : ('a' + high - 10);
		buff += (low < 10) ? ('0' + low) : ('a' + low - 10);
	}
	return buff;
}
//16进制字符串 转 字节数组
void hexStringToBytes(const std::string& hex, BYTE* bytes)
{
	int bytelen = hex.length() / 2;
	std::string strByte;
	unsigned int n;
	for (int i = 0; i < bytelen; i++)
	{
		strByte = hex.substr(i * 2, 2);
		sscanf_s(strByte.c_str(), "%x", &n);
		bytes[i] = n;
	}
}

// Logic and data behind the server's behavior.
class RemoteMethodsServiceImpl final : public RemoteMethods::Service {
  Status GetDeviceInfo(ServerContext* context, const Request* request,
	  Reply* reply) override {

	  std::cout << request->jsonpara() << std::endl;
	  Json::Reader reader;
	  Json::Value value;
	  if (reader.parse(request->jsonpara(), value))
	  {
		  std::cout << "bFlag:" << value["bFlag"].asInt() << std::endl;
		  std::cout << "pdwInfoLen:" << value["pdwInfoLen"].asInt() << std::endl;
	  }


	  std::cout << std::endl;
	  std::cout << std::endl;

	  Json::Value root;
	  unsigned char info[] = { 0x44,0x00,0x45 ,0x46 };
	  root["pbInfo"] = bytesToHexString(info, sizeof(info));
	  root["pdwInfoLen"] = sizeof(info);
	  std::string para = root.toStyledString();
	  std::cout << para << std::endl;
	  reply->set_jsonpara(para);
	  reply->set_resultcode(0);
	  return Status::OK;
  }

  Status LoadSymKey(ServerContext* context, const Request* request,Reply* reply) override {

	  //unsigned char out[300] = { 1 }; //测试
	  //hexStringToBytes("1122003344", out);
	  //std::cout << bytesToHexString(out, 1) << std::endl;
	  //std::cout << hexStringToString("323334") << std::endl;
	  //std::cout << encodeHexString("323334") << std::endl;

	  std::cout << request->jsonpara() << std::endl;
	  Json::Reader reader;
	  Json::Value value;
	  if (reader.parse(request->jsonpara(), value))
	  {
			std::cout << "bKeyType:" << value["bKeyType"].asInt() << std::endl;
			std::cout << "wKeyIndex:" << value["wKeyIndex"].asInt() << std::endl;
			std::cout << "bAlg:" << value["bAlg"].asInt() << std::endl;
			std::cout << "bProtectKeyType:" << value["bProtectKeyType"].asInt() << std::endl;
			std::cout << "wProtectKeyIndex:" << value["wProtectKeyIndex"].asInt() << std::endl;
			std::cout << "pbKeyData:" << value["pbKeyData"].asString() << std::endl;
			std::cout << "wKeyDataLen:" << value["wKeyDataLen"].asInt() << std::endl;
			std::cout << "pbKCV:" << value["pbKCV"].asString() << std::endl;
			std::cout << "bKCVLen:" << value["bKCVLen"].asInt() << std::endl;
			std::cout << "bKCVMode:" << value["bKCVMode"].asInt() << std::endl;
	  }

	
	  std::cout << std::endl;
	  std::cout << std::endl;

	  Json::Value root;
	  unsigned char kcv[] = { 0x44,0x00,0x45 ,0x46 };
	  root["pbKCV"] = bytesToHexString(kcv, sizeof(kcv));
	  std::string para = root.toStyledString();
	  std::cout << para << std::endl;
	  reply->set_jsonpara(para);
	  reply->set_resultcode(0);
	  return Status::OK;
  }

};


void RunServer() {
  std::string server_address("0.0.0.0:50051");
  RemoteMethodsServiceImpl service;

  grpc::EnableDefaultHealthCheckService(true);
  grpc::reflection::InitProtoReflectionServerBuilderPlugin();
  ServerBuilder builder;
  // Listen on the given address without any authentication mechanism.
  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
  // Register "service" as the instance through which we'll communicate with
  // clients. In this case it corresponds to an *synchronous* service.
  builder.RegisterService(&service);
  // Finally assemble the server.
  std::unique_ptr<Server> server(builder.BuildAndStart());
  std::cout << "Server listening on " << server_address << std::endl;

  // Wait for the server to shutdown. Note that some other thread must be
  // responsible for shutting down the server for this call to ever return.
  server->Wait();
}

int testmain(int argc, char** argv) {
  RunServer();
  return 0;
}

Client

#include <iostream>
#include <memory>
#include <string>
#include <json.h>
using namespace Json;
#define RPC_FAILED 9999



#include <grpcpp/grpcpp.h>

#ifdef BAZEL_BUILD
#include "examples/protos/pos.grpc.pb.h"
#else
#include "pos.grpc.pb.h"
#endif
using namespace std;
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using pos::RemoteMethods;
using pos::Reply;
using pos::Request;
using pos::Reply;

typedef unsigned char BYTE;
typedef unsigned char UCHAR;
typedef unsigned char *PUCHAR;
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef const void *LPCVOID;

typedef long LONG;
typedef const char *LPCSTR;
typedef const BYTE *LPCBYTE;
typedef BYTE *LPBYTE;
typedef DWORD *LPDWORD;
typedef char *LPSTR;

/* these types were deprecated but still used by old drivers and
 * applications. So just declare and use them. */


/* types unused by pcsc-lite */
typedef unsigned short WORD;

#ifndef IN
#define IN
#endif

#ifndef OUT
#define OUT
#endif


extern std::string encodeHexString(const std::string& str);
extern std::string hexStringToString(const std::string& hexStr);
extern std::string bytesToHexString(const BYTE* bytes, const int length);
extern void hexStringToBytes(const std::string& hex, BYTE* bytes);


class RemoteMethodsClient {
 public:
  RemoteMethodsClient(std::shared_ptr<Channel> channel)
      : stub_(RemoteMethods::NewStub(channel)) {}

  // Assembles the client's payload, sends it and presents the response back
  // from the server.

  DWORD LoadSymKey(IN BYTE bKeyType, IN WORD wKeyIndex, IN BYTE bAlg, IN BYTE bProtectKeyType, IN WORD wProtectKeyIndex, IN BYTE *pbKeyData, IN WORD wKeyDataLen,
	  IN OUT BYTE *pbKCV, IN BYTE bKCVLen, IN BYTE bKCVMode) {  
	  Request request;
	  Json::Value root;
	  root["bKeyType"] = bKeyType;
	  root["wKeyIndex"] = wKeyIndex;
	  root["bAlg"] = bAlg;
	  root["bProtectKeyType"] = bProtectKeyType;
	  root["wProtectKeyIndex"] = wProtectKeyIndex;
	  root["pbKeyData"] = bytesToHexString(pbKeyData, wKeyDataLen);
	  root["wKeyDataLen"] = wKeyDataLen;
	  root["pbKCV"] = bytesToHexString(pbKCV, bKCVLen);
	  root["bKCVLen"] = bKCVLen;
	  root["bKCVMode"] = bKCVMode;
	  std::string para = root.toStyledString();
	  std::cout << para << std::endl;
	  request.set_jsonpara(para);

	  Reply reply;
	  ClientContext context;
	  Status status = stub_->LoadSymKey(&context, request, &reply);
	  if (status.ok()) {
		  std::cout << "resultcode=" << reply.resultcode() << std::endl;
		  //std::cout << "jsonpara=" << reply.jsonpara() << std::endl;
		  Json::Reader reader;
		  Json::Value value;
		  if (reader.parse(reply.jsonpara(), value))
		  {
			  if (bKCVLen > 0)
			  {
				  std::string para = value["pbKCV"].asString();
				  std::cout << "pbKCV=" << para << std::endl;
				  hexStringToBytes(para, pbKCV);
			  }		 
		  }	
		  return reply.resultcode();
	  }
	  else {
		  std::cout << status.error_code() << ": " << status.error_message() << std::endl;
		  return RPC_FAILED;
	  }
  }

  DWORD GetDeviceInfo(OUT BYTE *pbInfo, IN OUT DWORD *pdwInfoLen, IN BYTE bFlag) {
	  Request request;
	  Json::Value root;

	  root["pdwInfoLen"] = (unsigned int)*pdwInfoLen;
	  root["bFlag"] = bFlag;

	  std::string para = root.toStyledString();
	  std::cout << para << std::endl;
	  request.set_jsonpara(para);

	  Reply reply;
	  ClientContext context;
	  Status status = stub_->GetDeviceInfo(&context, request, &reply); //
	  if (status.ok()) {
		  std::cout << "resultcode=" << reply.resultcode() << std::endl;
		  Json::Reader reader;
		  Json::Value value;
		  if (reader.parse(reply.jsonpara(), value))
		  {
			  hexStringToBytes(value["pbInfo"].asString(), pbInfo);
			  *pdwInfoLen = value["pdwInfoLen"].asInt();

		  }
		  return reply.resultcode();
	  }
	  else {
		  std::cout << status.error_code() << ": " << status.error_message() << std::endl;
		  return RPC_FAILED;
	  }
  }



 private:
  std::unique_ptr<RemoteMethods::Stub> stub_;
};

int main(int argc, char** argv) {
  // Instantiate the client. It requires a channel, out of which the actual RPCs
  // are created. This channel models a connection to an endpoint specified by
  // the argument "--target=" which is the only expected argument.
  // We indicate that the channel isn't authenticated (use of
  // InsecureChannelCredentials()).
  std::string target_str;
  std::string arg_str("--target");
  if (argc > 1) {
    std::string arg_val = argv[1];
    size_t start_pos = arg_val.find(arg_str);
    if (start_pos != std::string::npos) {
      start_pos += arg_str.size();
      if (arg_val[start_pos] == '=') {
        target_str = arg_val.substr(start_pos + 1);
      } else {
        std::cout << "The only correct argument syntax is --target="
                  << std::endl;
        return 0;
      }
    } else {
      std::cout << "The only acceptable argument is --target=" << std::endl;
      return 0;
    }
  } else {
    target_str = "localhost:50051";
  }
  RemoteMethodsClient remoteMethods(
      grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials()));


  unsigned char keyData[] = { 0x10,0x00,0x11 ,0x00 };
  unsigned char kcv[4] = { 0x20,0x00,0x21 ,0x00 };
  remoteMethods.LoadSymKey(1, 2, 3, 4, 5, keyData, sizeof(keyData), kcv,sizeof(kcv), 10);
  std::cout << "OUT pbKCV=" << bytesToHexString(kcv,sizeof(kcv)) << std::endl;

  unsigned char info[] = { 0x20,0x00,0x21 ,0x00 };
  DWORD infoLen = sizeof(info);
  remoteMethods.GetDeviceInfo(info, &infoLen, 5);
  std::cout << "OUT info=" << bytesToHexString(info, sizeof(info)) << std::endl;
  std::cin.get();
  return 0;
}

测试非常好用,30多个接口一天就改好了。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小黄人软件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值