zoukankan      html  css  js  c++  java
  • rpc远程调用开发

    RPC即远程过程调用,适用于集群管理,集群节点就是RPCServer,而我们发起远程调用的web服务器就是RPCClient。所以是少数rpcClient(可能一个)对多个RPCServer(集群节点)。

    今天讲述的RPC开发希望实现这样一个效果,在RPCClient上(也就是web服务器)执行一条shell命令,要求指定的远程主机执行指定的命令。命令的格式如下

    rpc_client  rpc_server_address command

    比如

    ./ssan_client 192.168.1.1 vmstat

    希望这条命令的远程执行(在RPCServer上)的结果直接在直接输出到web服务器(RPCClient)。可以先看一个执行效果。

    image

    image

    那么要做到这样一种效果,需要借助RPC框架,这里选择Apache Thrift, 并且使用C++语言,因为不能保证节点装什么PHP或JAVA环境,希望最后得到一个与环境无关的可执行文件。

    这里首先可以看到Apache官方C++教程

    https://thrift.apache.org/tutorial/cpp

    下面开始实现rpc。

    安装thrift环境

    下载相关文件

    yum -y groupinstall "Development Tools"
    wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
    wget http://ftp.gnu.org/gnu/bison/bison-2.5.1.tar.gz
    wget http://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz
    wget http://www.mirrorservice.org/sites/dl.sourceforge.net/pub/sourceforge/b/bo/boost/boost/1.55.0/boost_1_55_0.tar.gz
    git clone https://git-wip-us.apache.org/repos/asf/thrift.git

    依次安装

    tar zxf autoconf-2.69.tar.gz
    cd autoconf-2.69
    ./configure --prefix=/usr
    make
    sudo make install
    cd ..
    
    tar xvf bison-2.5.1.tar.gz
    cd bison-2.5.1
    ./configure --prefix=/usr
    make
    make install
    cd ..
    
    tar zxf automake-1.14.tar.gz
    cd automake-1.14
    ./configure --prefix=/usr
    make
    make install
    cd ..
    
    
    tar zxf boost_1_55_0.tar.gz
    ./bootstrap.sh
    ./configure
    make
    sudo make install
    
    cd ../thrift
    ./bootstrap.sh
    yum install openssl openssl-devel -y
    ./configure
    make
    make install

    这里在安装thrift是yum安装了openssl-dev,是为了解决这个错误

    Image

    安装完成之后

    Image

    编写thrift文件

    编写ssan.thrift文件

    namespace cpp ssan
    
    service SSANAgent {
      string run(1:string command)
    }

    这里定义了一个接口方法run,接收一个string类型的参数,表示要执行的命令

    使用thrift生成

    thrift -r --gen cpp ssan.thrift

    Image

    生成的源代码主要在SSANAgent.cpp中,可以翻看SSANAgent.h的定义。

    可以看到,我们只需要写一个类继承这个类,重写run方法,在run方法里实现业务,并且可以看到它帮我们添加了一个参数,这个参数用来做什么呢?用来返回结果。Thrift连这事都帮你准备好了

    编写rpcServer

    thrift已经为我们生成了server的模板

    cp SSANAgent_server.skeleton.cpp SSANServer.cpp

    之前定义的接口方法也主要定义在这个类里

    Image

    修改SSANServer.cpp文件

    // This autogenerated skeleton file illustrates how to build a server.
    // You should copy it to another filename to avoid overwriting it.
    
    #include "SSANAgent.h"
    #include <sstream>
    #include <thrift/protocol/TBinaryProtocol.h>
    #include <thrift/server/TSimpleServer.h>
    #include <thrift/transport/TServerSocket.h>
    #include <thrift/transport/TBufferTransports.h>
    
    using namespace ::apache::thrift;
    using namespace ::apache::thrift::protocol;
    using namespace ::apache::thrift::transport;
    using namespace ::apache::thrift::server;
    
    using boost::shared_ptr;
    
    using namespace  ::ssan;
    using namespace std;
    
    class SSANAgentHandler : virtual public SSANAgentIf {
     public:
      SSANAgentHandler() {
        // Your initialization goes here
      }
    
      void run(std::string& _return, const std::string& command) {
          std::ostringstream oss;
          FILE * pp = popen(command.c_str(),"r");
          if(pp){
              char buf[4096];
              while(fgets(buf,sizeof(buf),pp)){
                  oss << buf;
              }
              pclose(pp);
          }
          else{
              oss << "Error: No such command : " << command;
          }
          _return = oss.str();
      }
    };
    
    int main(int argc, char **argv) {
      int port = 9090;
      shared_ptr<SSANAgentHandler> handler(new SSANAgentHandler());
      shared_ptr<TProcessor> processor(new SSANAgentProcessor(handler));
      shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
      shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
      shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
    
      TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
      cout << "Start SSAN Server ..." << endl;
      server.serve();
      cout << "Done" << endl;
      return 0;
    }

    主要是在run方法里处理业务

    生成rpcServer

    先不借助Makefile,依次执行下面的命令编译

    g++ -Wall -I/usr/local/include/thrift -c SSANAgent.cpp
    g++ -Wall -I/usr/local/include/thrift -c SSANServer.cpp
    g++ -Wall -I/usr/local/include/thrift -c ssan_constants.cpp
    g++ -Wall -I/usr/local/include/thrift -c ssan_types.cpp

    链接文件生成rpcServer,注意这里是动态链接

    g++ -L/usr/local/lib *.o -o ssan_server –lthrift

    链接后运行出现这个错误

    Image

    这个文件其实已经存在了,不过在目录/usr/local/lib/下,而程序运行时再/usr/lib下搜索动态库文件,所以建立一个软链接

    ln -s /usr/local/lib/libthrift-1.0.0-dev.so /usr/lib/libthrift-1.0.0-dev.so

    Image

    再执行就成功启动了

    Image

    编写rpcClient

    rpcClient代码需要自己创建,头文件除了server部分,其他地方照抄就是了

    #include "SSANAgent.h"
    
    #include <ostream>
    #include <sstream>
    
    #include <thrift/protocol/TBinaryProtocol.h>
    #include <thrift/transport/TServerSocket.h>
    #include <thrift/transport/TBufferTransports.h>
    #include <thrift/transport/TSocket.h>
    
    using namespace ::apache::thrift;
    using namespace ::apache::thrift::protocol;
    using namespace ::apache::thrift::transport;
    
    using namespace ssan;
    using namespace std;
    
    int main(int argc,char ** argv){
        if(argc < 3){
            printf("Usage: %s ip-address command ...
    ",argv[0]);
            return -1;
        }
        //  处理输入参数
        ostringstream command,address;
        address << argv[1];
        if(argc > 2){
            command << argv[2];
            for(int i=3;i < argc;i++){
                command << " " << argv[i];
            }
        }
        //  访问rpc server执行命令
        boost::shared_ptr<TSocket> socket(new TSocket(address.str().c_str(),9090));
        boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
        boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
    
        SSANAgentClient client(protocol);
        string output;
    
        transport->open();
    
        client.run(output,command.str());
        cout << output << endl;
    
        transport->close();
        return 0;
    }

    这里实例化了一个SSANAgentClient,它也定义在SSANAgent.h文件中,并且也继承自SSANAgentIf,所以它也有run方法,并且可以看到它的run方法做了两件事情,将命令发送给server执行,接收server返回的结果。

    生成rpcClient

    编译

    g++ -Wall -I/usr/local/include/thrift -c SSANClient.cpp

    链接

    g++ -L/usr/local/lib SSANClient.o SSANAgent.o ssan_constants.o ssan_types.o -o ssan_client -lthrift

    这部分基本没出什么大问题

    编写Makefile编译

    为了更方便的调试代码,还是需要写一个Makefile文件。时间有限,这个是临时写的,后面会继续完善

    LIB_INC     =-L/usr/local/lib
    SHARE_OBJ   =ssan_constants.o ssan_types.o 
    all : server client
    
    server: SSANAgent.o SSANServer.o $(SHARE_OBJ)
        g++ $(LIB_INC) $^ -o ssan_server -lthrift
        @echo ssan_server created.
    
    client: SSANAgent.o SSANClient.o $(SHARE_OBJ)
        g++ $(LIB_INC) $^ -o ssan_client -lthrift
        @echo ssan_client created.
    
    #default:server client
    
    clean :
        -rm *.o ssan_client ssan_server
        @echo cleanup done;

    执行make,可以看到这样的效果

    image

    至此,RPCServer和RPCClient都已经生成了,下一步就是解决静态编译的问题。因为时间有限,这个将会在下一篇博客中PHP对RPC服务的调用封装中写出

  • 相关阅读:
    开放源码的对象关系映射工具ORM.NET 插入数据 Insert/Update Data
    开放源码的对象关系映射工具ORM.NET 快档开发入门 Quick Start
    .NET 动态脚本语言Script.NET 开发指南
    开放源码的对象关系映射工具ORM.NET 删除数据 Deleting Records using ORM.NET
    .NET Remoting过时了吗?为什么公司的项目还是选择用.NET Remoting,而不是WCF?
    开放源码的对象关系映射工具ORM.NET 查看和显示数据 View and Display data using ORM.NET
    开放源码的对象关系映射工具ORM.NET 查询表 调用存储过程 增加自定义代码
    技术人生:坚持,每日一博
    CQRS:CQRS + DDD + MDP 实现快速应用程序开发
    NodeJs:Happy代码生成器,重构了代码,更新了文档,完善了示例,欢迎下载使用
  • 原文地址:https://www.cnblogs.com/lvyahui/p/4789711.html
Copyright © 2011-2022 走看看