GRPC学习初级阶段

主要记录下使用gRPC躺过的坑

1. GRPC c++版安装

  • 在github上搜索grpc(https://github.com/grpc/grpc),我选择的版本是v1.22.1(需要在火狐浏览器中打开才能选择分支)
  • 注意不要直接下载源码,这样无法获取grpc依赖的三方库,thirty_party文件夹会为空
  • 下载完整的源码前需要做一些准备工作,可从BUILDING.md文件中查找,具体步骤如下:
  1. 下载并安装git
    https://git-scm.com/
  2. 下载安装choco
    https://blog.csdn.net/u010570551/article/details/72936663
    3.安装ActivePerl,在cmd中执行
    choco install activeperl
  3. 安装golang,在cmd中执行
    choco install golang
  4. 安装yasm并设置环境变量,在cmd中执行
    choco install yasm
  5. 下载grpc源码,在cmd中执行以下命令
    git clone --recursive -b master(v1.22.1) https://github.com/grpc/grpc(可以指定特定版本)
  6. cd grpc/third_party/protobuf
    Cmake GUI生成protobuf的解决方案,并用VS2017编译生成库
  7. cd grpc
    Cmake GUI生成grpc的解决方案,并用VS2017编译生成库
  8. 利用protoc.exe和grpc_cpp_plugin.exe生成proto文件对应的.h和.cc文件

2. GRPC c#版安装

  • 右键工程->管理NuGet程序包->浏览,分别搜索grpc,grpc.tools,Google.Protobuf并安装,注意针对每个工程右键,而不是直接在解决方案上右键
  • 利用protoc.exe及grpc插件生成ProtocolGrpc.cs和Protocol.cs文件
//注意proto3中,若需要判断基本变量是否为空,需要封装基本变量,具体见wrappers.proto
protoc.exe --csharp_out=.\ mcsf_iron_man_protocol.proto --include_imports wrappers.proto
protoc.exe --grpc_out=.\ --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe *protocol.proto

3.GRPC demo

定义协议

//定义服务的代码,放在刚创建的helloworld.proto中
 
syntax = "proto3";
package gRPCDemo;
service gRPC {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}
 
message HelloRequest {
  string name = 1;
}
 
message HelloReply {
  string message = 1;
}

C#版客户端代码


//客户端代码
 
using Grpc.Core;
using GRPCDemo;
using System;
 
namespace gRPCClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Channel channel = new Channel("127.0.0.1:9007", ChannelCredentials.Insecure);
 
            var client = new gRPC.gRPCClient(channel);
            var reply = client.SayHello(new HelloRequest { Name = "Zhang San" });
            Console.WriteLine("来自" + reply.Message);
 
            channel.ShutdownAsync().Wait();
            Console.WriteLine("任意键退出...");
            Console.ReadKey();
        }
    }
}

C#版服务端代码

//服务端代码
 
using Grpc.Core;
using GRPCDemo;
using System;
using System.Threading.Tasks;
 
namespace gRPCServer
{
    class severProgram
    {
        const int Port = 9007;
 
        public static void Main(string[] args)
        {
            Server server = new Server
            {
                Services = { gRPC.BindService(new gRPCImpl()) },
                Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) }
            };
            server.Start();
 
            Console.WriteLine("gRPC server listening on port " + Port);
            Console.WriteLine("任意键退出...");
            Console.ReadKey();
 
            server.ShutdownAsync().Wait();
        }
    }
 
    class gRPCImpl : gRPC.gRPCBase
    {
        // 实现SayHello方法
        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
        }
    }
 
}

C++版客户端

#include "../GrpcCPlusDemo/hello.pb.h"
#include "../GrpcCPlusDemo/hello.grpc.pb.h"

#include "grpcpp/create_channel.h"
#include "grpcpp/Channel.h"
#include "grpcpp/security/credentials.h"

//实现proto协议中定义的RPC服务
class HelloClientImpl
{
public:
	HelloClientImpl(std::shared_ptr < grpc::Channel > channel) :stub_(gRPCDemo::gRPC::NewStub(channel)) {}
	std::string InvokeCallRPC(const std::string v)
	{
		gRPCDemo::HelloRequest request;
		request.set_name(v);

		gRPCDemo::HelloReply reply;
		grpc::ClientContext context;
		grpc::Status status = stub_->SayHello(&context, request, &reply);
		if (status.ok())
		{
			return reply.message();
		}
		else
		{
			std::cout << status.error_code() << ":" << status.error_message() << "InvokeCallRPC Failed" << std::endl;
			return "";
		}

		return 0;
	}
private:
	std::unique_ptr<gRPCDemo::gRPC::Stub> stub_;
};


int main()
{
	HelloClientImpl client(grpc::CreateChannel("127.0.0.1:9009", grpc::InsecureChannelCredentials()));
	std::string str = client.InvokeCallRPC("Jim");
	std::cout << "client received :" << str << std::endl;
	return 0;
}

C++版服务端

#include "../GrpcCPlusDemo/hello.pb.h"
#include "../GrpcCPlusDemo/hello.grpc.pb.h"

#include "grpcpp/server_builder.h"


//实现proto协议中定义的RPC服务
class HelloServiceImpl : public gRPCDemo::gRPC::Service
{
public:
	virtual ::grpc::Status SayHello(::grpc::ServerContext* context, const gRPCDemo::HelloRequest* req, gRPCDemo::HelloReply* respond)
	{
		respond->set_message("hello,client");
		return grpc::Status::OK;
	}

};

//启动服务,监听指定端口
void RunServer()
{
	std::string server_address("127.0.0.1:50057");
	HelloServiceImpl service;

	grpc::ServerBuilder builder;
	builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
	builder.RegisterService(&service);
	std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
	std::cout << "Server Listening on " << server_address << std::endl;
	server->Wait();
}


int main()
{
	RunServer();
	return 0;
}

4. 几点注意

  • grpc是跨语言跨平台通信框架,虽然C++和C#对同一份proto协议生成的文件或接口有所区别,但并不妨碍通信,grpc内部会做处理
  • c++和C#版本可以不一致,而且不确定两者的版本是否具有对应关系,因为c++一般是从github上获取指定版本的grpc源码(目前最高release版本为1.23.0),然后编译成库进行使用,而C#的源码编译时会报强名称的错,提示snk文件被占用,其实文件一直在那,没被占用,不知道啥原因,目前C#版grpc一般通过NuGet获取,获取时一定要注意,NuGet获取三方库时,会自动生成一个package.config的文件,里面会记录三方库所依赖的其他库,千万不要自己手动添加,不然package.config会缺少文件,导致通信失败的
  • 目前C#版是在.Net Framework上运行的,但看官网资料,一般都是基于.net Core,所以建议后面使用的话基于.Net Core框架来使用GRPC

5 参考

https://www.grpc.io/
https://blog.csdn.net/img_Guo/article/details/86096604
http://doc.oschina.net/grpc?t=57966

猜你喜欢

转载自blog.csdn.net/tianzhiyi1989sq/article/details/101048779
今日推荐