文章目录
- Mac gRPC for C
- #0 源码
- #1 环境
- #2 安装
- #3 开始
- #3.1 说明
- #3.2 目录结构
- #3.3 proto文件
- #3.4 gRPC服务端(C )
- #3.6 gRPC客户端(Python/C )
- #3.6.1 Python
- #3.6.2 C
- #3.7 效果
- #4 遇到的问题
Mac gRPC for C
#0 源码
Mac: https://github.com/Coxhuang/FKCpp/tree/master/gRPCDemo/macOS
Ubuntu: https://github.com/Coxhuang/FKCpp/tree/master/gRPCDemo/ubuntu
#1 环境
代码语言:javascript复制C 14
Python 3.8
macOS 10.5.15
Ubuntu 16.04
cmake 3.18.2
proto 3
Clion
#2 安装
- macOS
使用brew安装
- Ubuntu
- 安装依赖
sudo apt-get install pkg-config
sudo apt-get install autoconf automake libtool make g unzip
sudo apt-get install libgflags-dev libgtest-dev
sudo apt-get install clang libc -dev
- 下载grpc源码(国内镜像)
git clone https://gitee.com/mirrors/grpc-framework grpc
- 修改 submodule
代码语言:javascript复制GitHub的submodule下载很慢很慢, 一天都下不下来
cd grpc
cat .gitmodules // 查看文件里的submodule, 将GitHub改成Gitee
- 更新submodule
cd grpc
git submodule update --init
- 安装gRPC
cd grpc
mkdir build
cd build
// 指定安装路径 /usr/local
cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j2
sudo make install
#3 开始
#3.1 说明
- 使用前需要安装gRPC
- C 实现gRPC服务端(CMake编译)
- Python/C 实现gRPC客户端(两种语言实现客户端)
#3.2 目录结构
代码语言:javascript复制.
├── client.py
├── macOS
│ ├── client_cpp
│ │ ├── CMakeLists.txt
│ │ ├── build
│ │ └── main.cpp
│ ├── protos
│ │ ├── helloworld.grpc.pb.cc
│ │ ├── helloworld.grpc.pb.h
│ │ ├── helloworld.pb.cc
│ │ ├── helloworld.pb.h
│ │ ├── helloworld.proto
│ │ ├── helloworld_pb2.py
│ │ └── helloworld_pb2_grpc.py
│ └── server_cpp
│ ├── CMakeLists.txt
│ ├── build
│ └── main.cpp
└── ubuntu
├── client_cpp
│ ├── CMakeLists.txt
│ └── main.cpp
├── protos
│ ├── helloworld.grpc.pb.cc
│ ├── helloworld.grpc.pb.h
│ ├── helloworld.pb.cc
│ ├── helloworld.pb.h
│ ├── helloworld.proto
│ ├── helloworld_pb2.py
│ └── helloworld_pb2_grpc.py
└── server_cpp
├── CMakeLists.txt
└── main.cpp
#3.3 proto文件
helloworld.proto
代码语言:javascript复制syntax = "proto3";
option java_package = "ex.grpc";
package helloworld;
message Reply {
int32 result = 1;
}
message HelloMessage {
int32 a = 1;
int32 b = 2;
}
service TestServer {
rpc hello_request (HelloMessage) returns (Reply) {}
}
生成c 和python对应的文件
注意: 生成.cc或者.h文件, macOS和Ubuntu两个平台的文件内容不一样,也就是说,不可以将在Mac下生成的*.cc和*.h文件在Ubuntu下使用**
- C
cd protos
protoc --cpp_out=. helloworld.proto
protoc --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` helloworld.proto
生成:
helloworld.grpc.pb.cc
helloworld.grpc.pb.h
helloworld.pb.cc
helloworld.pb.h
- Python
cd protos
python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. helloworld.proto
生成:
helloworld_pb2_grpc.py
helloworld_pb2.py
#3.4 gRPC服务端(C )
macOS下的代码,macOS和Ubuntu只有CMakeLists.txt不一样,具体的差异情况我的GitHub源码
不是说CMake是跨平台吗,为什么在macOS和Ubuntu的CMakeLists.txt不一样???
因为我在安装gPRC时,Mac使用brew安装,不是源码安装,导致在Mac下CMakeLists.txt不能使用find_package
main.cpp
代码语言:javascript复制#include <string>
#include <grpcpp/grpcpp.h>
#include "protos/helloworld.grpc.pb.h"
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using helloworld::TestServer;
using helloworld::HelloMessage;
using helloworld::Reply;
class HelloServiceImplementation final : public TestServer::Service {
Status hello_request(
ServerContext* context,
const HelloMessage* request,
Reply* reply
) override {
int a = request->a();
int b = request->b();
reply->set_result(a * b);
return Status::OK;
}
};
void Run() {
std::string address("0.0.0.0:5000");
HelloServiceImplementation service;
ServerBuilder builder;
builder.AddListeningPort(address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on port: " << address << std::endl;
server->Wait();
}
int main(int argc, char** argv) {
Run();
return 0;
}
CMakeLists.txt
代码语言:javascript复制macOS (macOS和Ubuntu的CMakeLists.txt不一样)
cmake_minimum_required(VERSION 3.17)
project(grpcdemo)
set(CMAKE_CXX_STANDARD 14)
find_package(Protobuf REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GRPCPP REQUIRED grpc >=1.22.0)
include_directories(
${GRPCPP_INCLUDE_DIRS} # /usr/local/Cellar/grpc/1.29.1/include
${Protobuf_INCLUDE_DIRS} # /usr/local/include
)
link_directories(
${GRPCPP_LIBRARY_DIRS}
)
add_library(hellolibrary ../protos/helloworld.grpc.pb.cc ../protos/helloworld.pb.cc )
target_link_libraries(hellolibrary
protobuf::libprotobuf # 将protobuf加到hellolibrary, 因为在hellolibrary 使用了protobuf
)
add_executable(server_bin main.cpp)
target_link_libraries(server_bin
${GRPCPP_LIBRARIES}
hellolibrary
)
#3.6 gRPC客户端(Python/C )
#3.6.1 Python
client.py
代码语言:javascript复制import grpc
from protos import helloworld_pb2
from protos import helloworld_pb2_grpc
from google.protobuf.json_format import ParseDict
import time
class HelloBusiness(object):
def __init__(self):
super(HelloBusiness, self).__init__()
self.ip = "127.0.0.1"
self.port = 5000
self.client_init()
def client_init(self):
"""
gRPC客户端初始化
:return: None
"""
self.channel = grpc.insecure_channel('{}:{}'.format(self.ip, self.port))
self.client = helloworld_pb2_grpc.TestServerStub(self.channel)
return None
def hello_business(self, msg):
"""
:param msg: request msg
:return:
"""
proto_data = helloworld_pb2.HelloMessage() #
ParseDict(msg, proto_data) # 格式化msg
response = self.client.hello_request.future(proto_data) # 向server发送数据
response.add_done_callback(self.hello_callback) # 回调函数, 发送数据使用异步[future]时, 必须加回调函数
return response
def hello_callback(self, future):
print(future.result().result)
print("callback")
class HelloWorld(HelloBusiness):
def hello(self, *args, **kwargs):
"""
:return: None
"""
self.hello_business({
"a": 1,
"b": 2,
})
return None
grpc_client = HelloWorld()
if __name__ == '__main__':
grpc_client.hello()
time.sleep(2)
#3.6.2 C
代码语言:javascript复制#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "../protos/helloworld.grpc.pb.h"
#endif
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using helloworld::TestServer;
using helloworld::HelloMessage;
using helloworld::Reply;
class GreeterClient {
public:
GreeterClient(std::shared_ptr<Channel> channel):stub_(TestServer::NewStub(channel)) {}
int say_hello(const std::string& user) {
HelloMessage request;
Reply reply;
ClientContext context;
request.set_a(21);
request.set_b(22);
Status status = stub_->hello_request(&context, request, &reply);
if (status.ok()) {
return reply.result();
} else {
std::cout << status.error_code() << ": " << status.error_message() << std::endl;
return 0;
}
}
private:
std::unique_ptr<TestServer::Stub> stub_;
};
int main(int argc, char** argv) {
GreeterClient greeter(grpc::CreateChannel("127.0.0.1:5000", grpc::InsecureChannelCredentials()));
std::string user("world");
int reply = greeter.say_hello(user);
std::cout << "Greeter received: " << reply << std::endl;
return 0;
}
CMakeLists.txt
代码语言:javascript复制macOS (macOS和Ubuntu的CMakeLists.txt不一样)
cmake_minimum_required(VERSION 3.17)
project(grpcdemo)
set(CMAKE_CXX_STANDARD 14)
find_package(Protobuf REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GRPCPP REQUIRED grpc >=1.22.0)
include_directories(
${GRPCPP_INCLUDE_DIRS} # /usr/local/Cellar/grpc/1.29.1/include
${Protobuf_INCLUDE_DIRS} # /usr/local/include
)
link_directories(
${GRPCPP_LIBRARY_DIRS}
)
add_library(hellolibrary ../protos/helloworld.grpc.pb.cc ../protos/helloworld.pb.cc )
target_link_libraries(hellolibrary
protobuf::libprotobuf # 将protobuf加到hellolibrary, 因为在hellolibrary 使用了protobuf
)
add_executable(client_bin main.cpp)
target_link_libraries(client_bin
${GRPCPP_LIBRARIES}
hellolibrary
)
#3.7 效果
- gRPC服务端
- gRPC客户端
#4 遇到的问题
- google/protobuf/port_def.inc
'google/protobuf/port_def.inc' file not found
#include <google/protobuf/port_def.inc>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
原因: CMakeLists.txt中没有添加protobuf的头文件
解决 : include_directories( ${Protobuf_INCLUDE_DIRS} )
- 无法找到gRPC
CMake Error at CMakeLists.txt:14 (find_package):
By not providing "FindgRPC.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "gRPC", but
CMake did not find one.
Could not find a package configuration file provided by "gRPC" with any of
the following names:
gRPCConfig.cmake
grpc-config.cmake
Add the installation prefix of "gRPC" to CMAKE_PREFIX_PATH or set
"gRPC_DIR" to a directory containing one of the above files. If "gRPC"
provides a separate development package or SDK, be sure it has been
installed.
原因: find_package(gRPC)
解决 : 将find_package(gRPC) 该为: find_package(PkgConfig REQUIRED) pkg_check_modules(GRPCPP REQUIRED grpc >=1.22.0)