手搓rpc基于zookeeper实现分布式搭建

本篇文章是针对:https://blog.csdn.net/T_Solotov/article/details/124170856中的项目的运行实例:
2、./userservice -i config.ini
//执行文件,需要一个配置文件,配置文件需要将zookeeper服务器运行起来
3、如何将zookeeper服务器运行起来:https://blog.csdn.net/lamfang/article/details/108866448或者https://blog.csdn.net/qq_52595134/article/details/123467180
4、zookeeper服务器需要java环境,安装java环境:https://blog.csdn.net/weixin_44904239/article/details/137240064
5、运行./userservice -i config.ini
运行成功,此时再12345端口上正在运行RPC服务;可以使用客户端连接到该服务;
6、运行./calluserservice -i 1config.ini 也就是rpc客户端连接rpc服务端

我的配置文件config.ini
rpc客户端和服务端都使用的这个配置文件

# RPC 服务端配置
rpcserverip = 128.0.0.1
rpcserverport = 12345

# ZooKeeper 服务端配置
zookeeperip = 127.0.0.1
zookeeperport = 2181

验证:
在这里插入图片描述

完整执行流程过程(完整过程看这里嗷)

1、通过CMakefile文件生成库

修改一下每个源文件的包含头文件地址;
建立一个build文件夹,在这个文件夹下,进行cmake …/src/;然后再make;发现报错:

/home/kk/workSpace/yyg_rpc_server/src/rpcheader.pb.cc:175:59: error: ‘ReadVarint32’ is not a member of ‘google::protobuf::internal’; did you mean ‘ReadVarint’?
175 | args_size_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
| ^~~~~~~~~~~~
按提示修改报错即可;此时再次进行make继续报错
/home/kk/workSpace/yyg_rpc_server/src/zookeeperutil.cc:68:16: error: ‘zoo_exists’ was not declared in this scope; did you mean ‘zoo_aexists’?
68 | flag = zoo_exists(m_zhandle, path, 0, nullptr);
| ^~~~~~~~~~
| zoo_aexists
/home/kk/workSpace/yyg_rpc_server/src/zookeeperutil.cc:72:24: error: ‘zoo_create’ was not declared in this scope; did you mean ‘zoo_acreate’?
72 | flag = zoo_create(m_zhandle, path, data, datalen,
| ^~~~~~~~~~
| zoo_acreate
/home/kk/workSpace/yyg_rpc_server/src/zookeeperutil.cc: In member function ‘std::string ZkClient::GetData(const char*)’:
/home/kk/workSpace/yyg_rpc_server/src/zookeeperutil.cc:92:20: error: ‘zoo_get’ was not declared in this scope; did you mean ‘zoo_aget’?
92 | int flag = zoo_get(m_zhandle, path, 0, buffer, &bufferlen, nullptr);
| ^~~~~~~
| zoo_aget
这个错误是因为异步和同步函数的问题,我们使用的函数是同步函数,但是在zookeeper.h的头文件中默认打开的是异步的,所以我们要跳转过去打开同步的函数;解决办法:跳转到zookeeper.h看到是ifdef THREADED控制的同步代码,所以我们要在包含此头文件之前写明ifdef THREADED(也就是在include/zookeeperutil.h中写) 之后再次make;成功,可以看到build文件夹下出现了一个libmprpc.a库

2、编写protoc文件

syntax = "proto3";
package fixbug;
option cc_generic_services = true;
message LoginRequest {
    bytes name = 1;
    bytes pwd = 2;
}

message LoginResponse {
    ResultCode result = 1;
    bool success = 2;
}

message RegisterRequest {
    uint32 id = 1;
    string name = 2;
    string pwd = 3;
}

message RegisterResponse {
    ResultCode result = 1;
    bool success = 2;
}

message ResultCode {
    int32 errcode = 1;
    string errmsg = 2;
}

service UserServiceRPC {
    rpc Login(LoginRequest) returns (LoginResponse);
    rpc Register(RegisterRequest) returns (RegisterResponse);
}

编译命令;

protoc --cpp_out=./ user.proto 

生成user.pb.cc和user.pb.h文件;

3、编写服务端实现代码和客户端实现代码;

userserver.cc//服务端

/***
文件注释:
文件名:  userservice.cc
callee端代码:callee提供caller想要调用的Login函数。
***/
#include <iostream>
#include <string>
#include "user.pb.h"
#include "mprpcapplication.h"
#include "rpcprovider.h"
class UserService : public fixbug::UserServiceRPC // 使用在rpc服务发布端(rpc服务提供者)
{
public:
    bool Login(std::string name, std::string pwd)
    {
        /**** 业务层代码 ****/
        std::cout << "doing local service: Login" << std::endl;
        std::cout << "name:" << name << " pwd:" << pwd << std::endl;
        return false;
    }
    void Register(::google::protobuf::RpcController* controller,
                       const ::fixbug::RegisterRequest* request,
                       ::fixbug::RegisterResponse* response,
                       ::google::protobuf::Closure* done)
    {
        std::cout << "hhh" << std::endl;
    }
    void Login(::google::protobuf::RpcController* controller,
                       const ::fixbug::LoginRequest* request,
                       ::fixbug::LoginResponse* response,
                       ::google::protobuf::Closure* done)
    {
		/**** callee要继承UserServiceRpc并重写它的Login函数 ****/
        
        std::string name = request->name();
        std::string pwd = request->pwd();
        //request存着caller发来的Login函数需要的参数
        
        bool login_result = Login(name, pwd);
        //处理Login函数的逻辑,这部分逻辑单独写了一个函数。处于简化目的,就只是打印一下name和pwd。
        
        fixbug::ResultCode *code = response->mutable_result();
        code->set_errcode(0);
        code->set_errmsg("");
        response->set_success(login_result);
        //将逻辑处理结果写入到response中。
        
        done->Run();
        //将结果发送回去
    }
};

int main(int argc, char **argv)
{
    MprpcApplication::Init(argc, argv);
	//想要用rpc框架就要先初始化
    
    RpcProvider provider;
    // provider是一个rpc对象。它的作用是将UserService对象发布到rpc节点上,暂时不理解没关系!!
    
    provider.NotifyService(new UserService());
    // 将UserService服务及其中的方法Login发布出去,供远端调用。
    // 注意我们的UserService是继承自UserServiceRpc的。远端想要请求UserServiceRpc服务其实请求的就是UserService服务。而UserServiceRpc只是一个虚类而已。

    provider.Run();
	// 启动一个rpc服务发布节点   Run以后,进程进入阻塞状态,等待远程的rpc调用请求
    return 0;
}


calluserserver.cc,客户端代码

/****
文件注释:
文件名: calluserservice.cc
caller端代码:caller向callee发起远端调用,即caller想要调用处于callee中的Login函数。
****/
#include <iostream>
#include "mprpcapplication.h"
#include "user.pb.h"
#include "mprpcchannel.h"
int main(int argc, char **argv)
{
    MprpcApplication::Init(argc, argv);
	//MprpcApplication类提供了解析argc和argv参数的方法,我们在终端执行这个程序的时候,需要通过-i参数给程序提供一个配置文件,这个配置文件里面包含了一些通信地址信息(后面提到)

    fixbug::UserServiceRPC_Stub stub(new MprpcChannel());
    //这一步操作后面会讲,这里就当是实例化UserServiceRpc_Stub对象吧。UserServiceRpc_Stub是由user.proto生成的类,我们之前在user.proto中注册了Login方法,
    
    fixbug::LoginRequest request;
    request.set_name("zhang san");
    request.set_pwd("123456");
  	//回想起我们的user.proto中注册的服务方法:
    // rpc Login(LoginRequest) returns(LoginResponse);
    // callee的Login函数需要参数LoginRequest数据结构数据
    
    fixbug::LoginResponse response;
    // callee的Login函数返回LoginResponse数据结构数据
    
    stub.Login(nullptr, &request, &response, nullptr); 
    //caller发起远端调用,将Login的参数request发过去,callee返回的结果放在response中。

    if (0 == response.result().errcode()) 
        std::cout << "rpc login response success:" << response.success() << std::endl;
    else
        std::cout << "rpc login response error : " << response.result().errmsg() << std::endl;
    //打印response中的内容,别忘了这个result和success之前在user.proto注册过
    return 0;
}

4、生成可执行文件

接下来根据库和写的proto消息生成的.cc一块编译,生成可执行文件;首先是服务端生成可执行文件:

g++ userservice.cc user.pb.cc -o ./../bin/userservice -L./../build -lmprpc -lprotobuf -lzookeeper_mt -lpthread -lmuduo_net -lmuduo_base

生成客户端执行代码:

g++ calluserserver.cc user.pb.cc -o ./../bin/calluserserver -L./../build -lmprpc -lprotobuf -lzookeeper_mt -lpthread -lmuduo_net -lmuduo_base

5、配置文件的创建

服务端和客户端都使用的此配置文件

# RPC 服务端配置
rpcserverip = 127.0.0.1
rpcserverport = 12345

# ZooKeeper 服务端配置
zookeeperip = 127.0.0.1
zookeeperport = 2181


6、启动zookeeper服务

1、查看当前zookeeper服务器是否在运行:

netstat -plnt | grep 2181

若无输出,说明没有运行,我们要去启动zookeeper服务器;(你需要去下载zookeeper,https://blog.csdn.net/lamfang/article/details/108866448或者https://blog.csdn.net/qq_52595134/article/details/123467180,参考gpt;
在这里插入图片描述

7、运行

服务端运行

./userservice -i config.ini

这样的话,服务端就被运行起来了;见下图:
在这里插入图片描述

客户端运行;

./userservice -i ./../config.ini

在这里插入图片描述

此时就完成了客户端和服务端的通信;

报错;
解决启动zookeeper时Could not find or Load main class org.apache.zookeeper.server.quorum.QuorumPeerMain的报错
两种办法,一是看README.txt文件,得到编译命令;sudo apt install maven mvn javadoc:aggregate
或者是直接下载带bin的压缩文件夹:https://blog.csdn.net/Melo_FengZhi/article/details/109121715

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值