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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章