微服务-gRPC的go和c++示例
一、环境搭建
1.1 go的gRPC环境搭建
1 protobuf环境搭建
# 安装 Go 的 Protocol Buffers 插件 `protoc-gen-go`(将protoc文件转为go文件) 并且引入protobuf相关go文件
go get -u github.com/golang/protobuf/protoc-gen-go
2 grpc环境搭建
go mod init 项目名称
go mod tidy`
go get -u google.golang.org/grpc
1.2 c++的gRPC环境搭建
1 protobuf环境搭建
参考:https://blog.csdn.net/weixin_54720578/article/details/132765947?spm=1001.2014.3001.5501
2 grpc环境搭建
参考:https://blog.csdn.net/weixin_54720578/article/details/132902296?spm=1001.2014.3001.5501
二、搭建一个微服务-go
2.1 服务端
1 编写proto文件
//文件位置:Server-gRPC/Profile/hello.proto
syntax = "proto3";
option go_package = "../Server"; //生成的go文件位于上一级文件下的Server文件下的Server包
service Server{ //服务
rpc SayHello(HelloRequest) returns (HelloReply){}
rpc GetMsg(HelloRequest) returns (HelloMessages){}
}
message HelloRequest{
string name = 1;
}
message HelloReply{
string message = 1;
}
message HelloMessages{
string msg = 1;
}
2 生成go文件
在Server-gRPC/Profile目录下运行如下脚本:
protoc --go_out=plugins=grpc:. hello.proto
运行后将会在Server-gRPC/Server目录下生成hello.pb.go文件
3 编写服务
//文件位置:Server-gRPC/Server/hello.go
package Server
import (
"context"
"fmt"
)
type HelloServer struct{}
func (hs *HelloServer) SayHello(ctx context.Context, in *HelloRequest) (*HelloReply, error) {
return &HelloReply{Message: "Hello"}, nil
}
func (hs *HelloServer) GetMsg(ctx context.Context, in *HelloRequest) (*HelloMessages, error) {
fmt.Println(in.Name)
return &HelloMessages{Msg: in.Name}, nil
}
4 开启服务
//文件位置:Server-gRPC/main.go
package main
import (
"Service-rpc/Server"
"fmt"
"net"
"google.golang.org/grpc"
)
func main() {
//开启网络监听
ln, err := net.Listen("tcp", "127.0.0.1:7777")
if err != nil {
fmt.Println(err)
}
//创建一个grpc服务
srv := grpc.NewServer()
//注册服务
Server.RegisterServerServer(srv, &Server.HelloServer{})
//服务开始监听
fmt.Println("wait.....")
err = srv.Serve(ln)
if err != nil {
fmt.Println(err)
}
}
2.2 客户端
1 编写proto文件
//文件位置:Client-gRPC/Profile/hello.proto
syntax = "proto3";
option go_package = "../Server"; //生成的go文件位于上一级文件下的Server文件下的Server包
service Server{ //服务
rpc SayHello(HelloRequest) returns (HelloReply){}
rpc GetMsg(HelloRequest) returns (HelloMessages){}
}
message HelloRequest{
string name = 1;
}
message HelloReply{
string message = 1;
}
message HelloMessages{
string msg = 1;
}
2 生成go文件
在Client-gRPC/Profile目录下运行如下脚本:
protoc --go_out=plugins=grpc:. hello.proto
运行后将会在Client-gRPC/Server目录下生成hello.pb.go文件
3 客户端调用服务
package main
import (
"Client-gRPC/Server"
"context"
"fmt"
"google.golang.org/grpc"
)
func main() {
//连接gPRC服务器
conn, err := grpc.Dial("127.0.0.1:7777", grpc.WithInsecure())
if err != nil {
fmt.Println(err)
}
defer conn.Close()
//创建rpc客户端
client := Server.NewServerClient(conn)
//创建请求数据
re := &Server.HelloRequest{Name: "zxh"}
//远程调用
reply, err := client.SayHello(context.Background(), re)
if err != nil {
fmt.Println(err)
}
fmt.Println("SayHello:" + reply.Message)
r, err := client.GetMsg(context.Background(), re)
if err != nil {
fmt.Println(err)
}
fmt.Println("GetMsg:" + r.Msg)
}
三、搭建一个微服务-c++
3.1 服务端
1 编写proto文件
//文件位置:Server-gRPC-c++/Profile/hello.proto
syntax = "proto3";
package HServer;
service HelloServer{ //服务
rpc SayHello(HelloRequest) returns (HelloReply){}
rpc GetMsg(HelloRequest) returns (HelloMessages){}
}
message HelloRequest{
string name = 1;
}
message HelloReply{
string message = 1;
}
message HelloMessages{
string msg = 1;
}
2 生成.h .cc文件
在Server-gRPC-c++/Profile/hello.proto中运行如下脚本
protoc --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` hello.proto
运行后将在Server-gRPC-c++/Profile中生成hello.grpc.pb.cc、hello.grpc.pb.h、hello.pb.cc、hello.pb.h文件
3 编写服务
//文件位置:Server-gRPC-c++/Server/hello.h
#include"../Profile/hello.grpc.pb.h"
#include<iostream>
using namespace std;
class HelloService final:public HServer::HelloServer::Service{
public:
grpc::Status SayHello(grpc::ServerContext* context,const HServer::HelloRequest* request,HServer::HelloReply* reply)override;
grpc::Status GetMsg(grpc::ServerContext* context,const HServer::HelloRequest* request,HServer::HelloMessages* hm)override;
};
//文件位置:Server-gRPC-c++/Server/hello.cpp
#include "hello.h"
grpc::Status HelloService::SayHello(
grpc::ServerContext *context,
const HServer::HelloRequest *request,
HServer::HelloReply *reply)
{
cout << "SayHello" << endl;
reply->set_message("hello this is cpp server");
return grpc::Status::OK;
}
grpc::Status HelloService::GetMsg(
grpc::ServerContext *context,
const HServer::HelloRequest *request,
HServer::HelloMessages *hm)
{
cout << request->name() << endl;
hm->set_msg(request->name());
return grpc::Status::OK;
}
4 开启服务
//文件位置:Server-gRPC-c++/main.cpp
#include<string>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include<grpc++/grpc++.h>
#include <grpcpp/health_check_service_interface.h>
#include "Service/hello.h"
using namespace std;
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using HServer::HelloRequest;
using HServer::HelloReply;
using HServer::HelloMessages;
using HServer::HelloServer;
int main(){
// 创建 gRPC 服务器
grpc::EnableDefaultHealthCheckService(true);
grpc::reflection::InitProtoReflectionServerBuilderPlugin();
grpc::ServerBuilder builder;
std::string server_address("0.0.0.0:50051"); // 监听地址和端口
// 添加监听地址
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
// 注册您的服务实现类
HelloService service;
builder.RegisterService(&service);
// 构建服务器
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cout << "wait.... " << server_address << std::endl;
// 阻塞并等待关闭
server->Wait();
return 0;
}
5 编译(makefile)
# 根目录的Makefile
# 定义编译器和编译选项
CXX := g++
CXXFLAGS := -std=c++11 -Wl,--no-as-needed -Wl,--as-needed
# 定义第三方库的头文件和库文件路径
THIRD_PARTY_LIB1 := -L/usr/local/lib `pkg-config --libs grpc++ grpc`
THIRD_PARTY_LIB2 := -lprotobuf
THIRD_PARTY_LIB3 := -lpthread
THIRD_PARTY_LIB4 := -ldl
THIRD_PARTY_LIB5 := -lssl
THIRD_PARTY_LIB6 := -lgrpc++_reflection
# 列出所有的源文件
SRCS_MAIN := main.cpp
SRCS_SERVER := Service/hello.cpp
SRCS_PEOFILE := Profile/hello.grpc.pb.cc Profile/hello.pb.cc
# 根据源文件生成目标文件的名字(替换.cpp为.o)
OBJS_MAIN := $(SRCS_MAIN:.cpp=.o)
OBJS_SERVER := $(SRCS_SERVER:.cpp=.o)
OBJS_PEOFILE = $(SRCS_PEOFILE:.cc=.o)
# 目标可执行文件名
TARGET := prog
# 编译规则
all: $(TARGET)
$(TARGET): $(OBJS_MAIN) $(OBJS_SERVER) $(OBJS_PEOFILE) #链接
$(CXX) $(CXXFLAGS) -o $@ $^ $(THIRD_PARTY_LIB1) $(THIRD_PARTY_LIB2) $(THIRD_PARTY_LIB3) $(THIRD_PARTY_LIB4) $(THIRD_PARTY_LIB5) $(THIRD_PARTY_LIB6)
%.o: %.cpp #编译
$(CXX) $(CXXFLAGS) -o $@ -g -c $<
# 清理生成的文件
clean:
rm -f $(OBJS_MAIN) $(OBJS_SERVER) $(OBJS_PEOFILE)
3.2 客户端
1 编写proto文件
//文件位置:Client-gRPC-c++/Profile/hello.proto
syntax = "proto3";
package HServer;
service HelloServer{ //服务
rpc SayHello(HelloRequest) returns (HelloReply){}
rpc GetMsg(HelloRequest) returns (HelloMessages){}
}
message HelloRequest{
string name = 1;
}
message HelloReply{
string message = 1;
}
message HelloMessages{
string msg = 1;
}
2 生成.h .cc文件
在Client-gRPC-c++/Profile/hello.proto中运行如下脚本
protoc --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` hello.proto
运行后将在Client-gRPC-c++/Profile中生成hello.grpc.pb.cc、hello.grpc.pb.h、hello.pb.cc、hello.pb.h文件
3 客户端
//文件位置:Client-gRPC-c++/main.cpp
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include"Profile/hello.pb.h"
#include "Profile/hello.grpc.pb.h"
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using HServer::HelloRequest;
using HServer::HelloReply;
using HServer::HelloMessages;
using HServer::HelloServer;
class HelloWorldClient {
public:
HelloWorldClient(std::shared_ptr<Channel> channel)
: stub_(HelloServer::NewStub(channel)) {}
std::string SayHello(const std::string& name) {
HelloRequest request;
request.set_name(name);
HelloReply reply;
ClientContext context;
Status status = stub_->SayHello(&context, request, &reply);
if (status.ok()) {
return reply.message();
} else {
std::cout << "RPC failed: " << status.error_message() << std::endl;
return "RPC failed";
}
}
std::string GetMsg(const std::string& name) {
HelloRequest request;
request.set_name(name);
HelloMessages reply;
ClientContext context;
Status status = stub_->GetMsg(&context, request, &reply);
if (status.ok()) {
return reply.msg();
} else {
std::cout << "RPC failed: " << status.error_message() << std::endl;
return "RPC failed";
}
}
private:
std::unique_ptr<HelloServer::Stub> stub_;
};
int main() {
HelloWorldClient client(grpc::CreateChannel("localhost:7777", grpc::InsecureChannelCredentials()));
std::string user("world");
std::string reply = client.SayHello(user);
std::cout << "Received: " << reply << std::endl;
return 0;
}
4 编译(makefile)
# 根目录的Makefile
# 定义编译器和编译选项
CXX := g++
CXXFLAGS := -std=c++11 -Wl,--no-as-needed -Wl,--as-needed
# 定义第三方库的头文件和库文件路径
THIRD_PARTY_LIB1 := -L/usr/local/lib `pkg-config --libs grpc++ grpc`
THIRD_PARTY_LIB2 := -lprotobuf
THIRD_PARTY_LIB3 := -lpthread
THIRD_PARTY_LIB4 := -ldl
THIRD_PARTY_LIB5 := -lssl
THIRD_PARTY_LIB6 := -lgrpc++_reflection
# 列出所有的源文件
SRCS_MAIN := main.cpp
SRCS_PEOFILE := Profile/hello.grpc.pb.cc Profile/hello.pb.cc
# 根据源文件生成目标文件的名字(替换.cpp为.o)
OBJS_MAIN := $(SRCS_MAIN:.cpp=.o)
OBJS_SERVER := $(SRCS_SERVER:.cpp=.o)
OBJS_PEOFILE = $(SRCS_PEOFILE:.cc=.o)
# 目标可执行文件名
TARGET := prog
# 编译规则
all: $(TARGET)
$(TARGET): $(OBJS_MAIN) $(OBJS_SERVER) $(OBJS_PEOFILE) #链接
$(CXX) $(CXXFLAGS) -o $@ $^ $(THIRD_PARTY_LIB1) $(THIRD_PARTY_LIB2) $(THIRD_PARTY_LIB3) $(THIRD_PARTY_LIB4) $(THIRD_PARTY_LIB5) $(THIRD_PARTY_LIB6)
%.o: %.cpp #编译
$(CXX) $(CXXFLAGS) -o $@ -g -c $<
# 清理生成的文件
clean:
rm -f $(OBJS_MAIN) $(OBJS_SERVER) $(OBJS_PEOFILE)