使用c++实现gRPC远程调用框架中传输文件,proto文件如下:
syntax = "proto3"; package transferfile; service TransferFile { rpc Upload(stream Chunk) returns (Reply) {} } message Chunk { bytes buffer = 1; } message Reply { int32 length = 1; }
对应的c++代码如下:
client端:
#include <iostream> #include <string> #include <fstream> #include <sys/time.h> #include <grpc/grpc.h> #include <grpc++/channel.h> #include <grpc++/client_context.h> #include <grpc++/create_channel.h> #include <grpc++/security/credentials.h> #include "transfer_file.grpc.pb.h" using grpc::Channel; using grpc::ClientContext; using grpc::ClientWriter; using grpc::Status; using transferfile::Chunk; using transferfile::Reply; using transferfile::TransferFile; #define CHUNK_SIZE 1024 * 1024
class TransferFileClient { public: TransferFileClient(std::shared_ptr<Channel> channel) : stub_(TransferFile::NewStub(channel)){}; void Upload();
private: std::unique_ptr<TransferFile::Stub> stub_; }; void TransferFileClient::Upload() { Chunk chunk; char data[CHUNK_SIZE]; Reply stats; ClientContext context; const char *filename = "./large_file_in"; std::ifstream infile; int len = 0; struct timeval start, end; gettimeofday(&start, NULL); infile.open(filename, std::ifstream::in | std::ifstream::binary); std::unique_ptr<ClientWriter<Chunk>> writer(stub_->Upload(&context, &stats)); while (!infile.eof()) { infile.read(data, CHUNK_SIZE); chunk.set_buffer(data, infile.gcount()); if (!writer->Write(chunk)) { // Broken stream. break; } len += infile.gcount(); } writer->WritesDone(); Status status = writer->Finish(); if (status.ok()) { gettimeofday(&end, NULL); std::cout << (end.tv_sec-start.tv_sec)+ (double)(end.tv_usec-start.tv_usec)/1000000 << std::endl; } else { std::cout << "TransferFile rpc failed." << std::endl; } }
int main(int argc, char** argv){ TransferFileClient guide(grpc::CreateChannel("localhost:10000", grpc::InsecureChannelCredentials())); guide.Upload(); return 0; }
server端:
#include <iostream> #include <fstream> #include <string> #include <grpc/grpc.h> #include <grpc++/server.h> #include <grpc++/server_builder.h> #include <grpc++/server_context.h> #include <grpc++/security/server_credentials.h> #include "transfer_file.grpc.pb.h" using grpc::Server; using grpc::ServerBuilder; using grpc::ServerContext; using grpc::ServerReader; using grpc::Status; using transferfile::Chunk; using transferfile::Reply; using transferfile::TransferFile; #define CHUNK_SIZE 1024 * 1024 class TransferFileImpl final : public TransferFile::Service { public: Status Upload(ServerContext* context, ServerReader<Chunk>* reader, Reply* reply); }; Status TransferFileImpl::Upload(ServerContext* context, ServerReader<Chunk>* reader, Reply* reply) { Chunk chunk; const char *filename = "./server_tmp"; std::ofstream outfile; const char *data;
outfile.open(filename, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary); while (reader->Read(&chunk)) { data = chunk.buffer().c_str(); outfile.write(data, chunk.buffer().length()); } long pos = outfile.tellp(); reply->set_length(pos); outfile.close(); return Status::OK; } void RunServer() { std::string server_address("0.0.0.0:50051"); TransferFileImpl service; ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<Server> server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; server->Wait(); } int main(int argc, char** argv) { RunServer(); return 0; }