grpc流式传输示例(c++)

目录

grpc理解

流式传输方式

Attention


grpc理解

grpc是结合protobuf的远程调用框架,服务端和客户端均支持同步和异步模式。同步模式下,服务器的service函数会阻塞,且当前线程不能再服务其它的client,类似于多线程模式,一个线程服务一个client,可通过ResourceQuota设置最大线程数;异步模式下,grpc提供类似poll方式管理事件,用户注册事件,并接收通知,一个线程管理一个CompletionQueue,通过轮询管理clients,线程模型可以用户自定义,在追求性能的情况下官方推荐异步模式。

grpc::ResourceQuota resource_quata;
resource_quata.SetMaxThreads(2);
builder.SetResourceQuota(resource_quata);

流式传输方式

grpc自定义的service函数可以定义流式的参数和返回值,对应的函数实现通过Reader,Writer,ReaderWriter实现用户自定义的逻辑,从而减少内存的使用,同时在部分数据到来时就可以进行数据处理。

proto文件

syntax="proto3";
package support;

service SupportGenerator{
    rpc GenSupport(stream STL) returns( stream STL){}
}

message Point{
    float x=1;
    float y=2;
    float z=3;
}

message STL {    
    repeated Point points=1;
}

服务端的代码如下

#pragma once
#include<memory>
#include<grpc++/grpc++.h>
#include"support.grpc.pb.h"
#include"support.pb.h"

//server impl
class SupportGeneratorService final :public support::SupportGenerator::Service
{
public://important
	grpc::Status GenSupport(grpc::ServerContext* context, grpc::ServerReaderWriter<support::STL, support::STL>* stl_reader_writer) override
	{
		vector<support::STL> stls_; //recv
		vector<support::Point> vertics_;//recv
		vector<float> coordinates_;//recv
		support::STL stl;//send
		while (stl_reader_writer->Read(&stl))
		{
			google::protobuf::RepeatedPtrField<support::Point> points = stl.points();
			CoutInLine("recieved from client ", points.size());
			stls_.emplace_back(stl);	
			for (auto& point : points)
			{
				vertics_.push_back(point);	
				coordinates_.push_back(point.x());
				coordinates_.push_back(point.y());
				coordinates_.push_back(point.z());
			}
		}		
        //return the request stl
		//for (auto stl_recieved : stls_)
		//{
		//	stl_reader_writer->Write(stl_recieved);
		//}		
		//return grpc::Status::OK;

		//handle	
#pragma region handle request
		
#pragma endregion

		auto support_vertics = what you return ;
		int once_count = 100;
		int loop_count = support_vertics.size() / once_count + 1;
		int index = 0;
		for (int loop = 0; loop < loop_count; loop++)
		{
			support::STL stl;
			for (int j = 0; j < once_count && index < support_vertics.size(); j++)
			{
				auto vertic = support_vertics[index++];
				auto point = stl.add_points();
				point->set_x(vertic.x);
				point->set_y(vertic.y);
				point->set_z(vertic.z);
			}
			stl_reader_writer->Write(stl);
		}
		return grpc::Status::OK;
	}
};

class HServer
{
public:

	HServer()
	{		
		grpc::ServerBuilder builder;
		builder.AddListeningPort("0.0.0.0:5000", grpc::InsecureServerCredentials());
		builder.RegisterService(&support_generator_service_);
		//对于同步server 的资源管理
		grpc::ResourceQuota resource_quata;
		resource_quata.SetMaxThreads(2);
		builder.SetResourceQuota(resource_quata);
		server_ = builder.BuildAndStart();
	}

	~HServer()
	{
		Stop();
	}

	void RunBackground();
	
	void Stop();

private:
	unique_ptr<grpc::Server> server_;	
	SupportGeneratorService support_generator_service_;
};

客户端代码

std::shared_ptr<grpc::Channel> channel = grpc::CreateChannel("127.0.0.1:5000", grpc::InsecureChannelCredentials());
	std::unique_ptr<support::SupportGenerator::Stub> stub = support::SupportGenerator::NewStub(channel);
		
	while (true)
	{
		getchar();
		grpc::ClientContext client_context;
		std::shared_ptr<grpc::ClientReaderWriter<support::STL, support::STL>> client_reader_writer(stub->GenSupport(&client_context));


        //recieved
        std::vector<support::Point> points;
		//read stl
        

        int n_vertics = vertics.size();
        int once_count = 100;
        int loop_count = n_vertics / once_count + 1;
        int index = 0;
		for (int loop = 0; loop < loop_count; loop++)
		{
            auto vertics = ReadStl("");//vertics should be read once_count every time in loop
			support::STL stl;
			for (int i = 0; i < once_count && index<n_vertics; i++)
			{
                
				auto point = stl.add_points();
				point->set_x(vertics[index].x());
				point->set_y(vertics[index].y());
				point->set_z(vertics[index].z());

                index++;
			}
			client_reader_writer->Write(stl);
			std::cout << "client write stl " << loop <<"   "<<index<< std::endl;
		}
		client_reader_writer->WritesDone();
		std::cout << "write done " <<index<< std::endl;

		support::STL stl;
		while (client_reader_writer->Read(&stl))
		{
            auto points_once = stl.points();
            for (auto& point : points_once)
            {
                points.emplace_back(point);//get all data in memory
            }
            Save("", points_once);//save by many times can reduce memory usage
			std::cout << "recieved from server  " <<points_once.size()<< std::endl;
		}
        std::cout << "recieved done  " << points.size() << std::endl;

        

Attention

protobuf 二进制序列化和反序列化需要protoc可执行文件产生序列化对象的相关代码;与grpc结合需要grpc自带的对应编程语言的插件产生服务基类的相关代码,二者版本需要相容。直接通过grpc安装protobuf。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的示例代码,用于在C++中使用gRPC进行文件传输: ```c++ #include <grpcpp/grpcpp.h> #include <grpcpp/create_channel.h> #include <grpcpp/security/credentials.h> #include <fstream> #include <iostream> #include "filetransfer.grpc.pb.h" using grpc::Channel; using grpc::ClientContext; using grpc::Status; using filetransfer::FileRequest; using filetransfer::FileReply; using filetransfer::FileTransfer; class FileTransferClient { public: FileTransferClient(std::shared_ptr<Channel> channel) : stub_(FileTransfer::NewStub(channel)) {} bool SendFile(const std::string& file_path) { std::ifstream file(file_path, std::ios::in | std::ios::binary); if (!file.is_open()) { std::cerr << "Failed to open file: " << file_path << std::endl; return false; } std::cout << "Sending file: " << file_path << std::endl; FileRequest request; request.set_file_name(file_path.substr(file_path.find_last_of("/") + 1)); char buffer[1024]; while (file.read(buffer, sizeof(buffer))) { request.set_file_content(buffer, sizeof(buffer)); ClientContext context; FileReply reply; Status status = stub_->SendFile(&context, request, &reply); if (!status.ok()) { std::cerr << "Failed to send file: " << status.error_message() << std::endl; return false; } } if (file.gcount() > 0) { request.set_file_content(buffer, file.gcount()); ClientContext context; FileReply reply; Status status = stub_->SendFile(&context, request, &reply); if (!status.ok()) { std::cerr << "Failed to send file: " << status.error_message() << std::endl; return false; } } std::cout << "File sent successfully!" << std::endl; return true; } private: std::unique_ptr<FileTransfer::Stub> stub_; }; int main(int argc, char** argv) { if (argc != 2) { std::cerr << "Usage: " << argv[0] << " <file_path>" << std::endl; return 1; } grpc::RegisterDefaultGrpcLibrary(); std::string server_address("localhost:50051"); FileTransferClient client(grpc::CreateChannel( server_address, grpc::InsecureChannelCredentials())); client.SendFile(argv[1]); return 0; } ``` 这个示例代码包括一个`FileTransferClient`类,它使用gRPC发送文件到服务器。主要的方法是`SendFile()`,它接受一个文件路径作为参数,并将该文件发送到服务器。 在`SendFile()`方法中,首先打开文件并检查是否成功。然后,创建一个`FileRequest`对象,并将文件名和缓冲区填充到文件内容中。使用`ClientContext`对象发送请求,等待响应,如果出现错误则返回false。最后,关闭文件并返回true。 注意:这个示例代码还需要一个服务端实现,可以根据需要自行实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值