• 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服务的调用封装中写出

  • 相关阅读:
    Phonon
    qt 的mysql的库
    vwmare下安装fedora
    C++标准库
    C#命名空间
    用谷歌Chrome浏览器来当手机模拟器
    Javascript实现ECMAScript 5中的map、reduce和filter函数
    页面变灰实现方案
    jQuery检查元素是否在视口内(屏幕可见区域内)
    兼容浏览器的获取指定元素(elem)的样式属性(name)的方法
  • 原文地址:https://www.cnblogs.com/lvyahui/p/4789711.html
Copyright © 2020-2023  润新知