rpc远程调用开发

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

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 ...\n",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服务的调用封装中写出

目录
相关文章
|
编解码 JSON 网络协议
Golang 语言使用标准库 net/rpc/jsonrpc 包跨语言远程调用
Golang 语言使用标准库 net/rpc/jsonrpc 包跨语言远程调用
109 0
|
3月前
|
负载均衡 网络协议 小程序
SpringCloud远程调用为啥要采用HTTP,而不是RPC?
【8月更文挑战第28天】在微服务架构日益盛行的今天,SpringCloud凭借其强大的生态系统和灵活的集成能力,成为了众多企业构建微服务系统的首选框架。在微服务之间的远程调用中,一个常见的问题是选择HTTP还是RPC(远程过程调用)作为通信协议。本文将深入探讨SpringCloud为何更倾向于采用HTTP而非RPC进行远程调用。
286 5
|
25天前
|
负载均衡 Java 开发者
Spring Cloud 远程调用:为何选择 HTTP 而非 RPC?
【10月更文挑战第1天】在微服务架构中,远程服务调用是一个核心环节。面对HTTP和RPC(Remote Procedure Call,远程过程调用)这两种通信协议,Spring Cloud 选择了HTTP作为其主要通信手段。本文将深入探讨Spring Cloud选择HTTP而非RPC的原因,以及这一选择在实际工作中的优势。
61 0
|
3月前
|
编解码 负载均衡 监控
RPC远程调用
RPC远程调用
|
6月前
|
网络协议 Java 程序员
SpringCloud 远程调用为啥要采用HTTP,而不是RPC?
关于SpringCloud远程调用采用HTTP而非RPC。
116 0
|
6月前
|
Go
Go语言RPC实战:打造自己的远程调用服务
Go语言RPC实战:打造自己的远程调用服务
139 0
|
6月前
|
JSON 负载均衡 网络协议
RPC远程调用协议
RPC远程调用协议
86 0
|
消息中间件 存储 缓存
远程调用RPC和消息MQ区别
远程调用RPC和消息MQ区别
111 0
|
XML 安全 数据格式
Python XML-RPC 实现简单的远程调用过程
RPC 是 Remote Procedure Call 的缩写,翻译成中文为:远程方法调用。在 Python 中,我们可以使用 XML-RPC 协议创建自己的跨平台,独立于语言的服务器。XML Remote Procedure Call,即 XML 远程方法调用。XML-RPC 是一种远程过程调用方法,它使用通过 HTTP 传递的 XML 作为载体。 有了它,客户端可以在远程服务器上调用带参数的方法(服务器以 URI 命名)并获取结构化的数据。 简单的理解是:将数据定义为 XML 格式,通过 HTTP 协议进行远程传输。
|
Dubbo Java 应用服务中间件
Dubbo+Zookeeper的简单使用---实现RPC远程调用
通过本篇博文,快速了解分布式相关知识并快速上手dubbo+Zookeeper实现RPC的远程调用。
Dubbo+Zookeeper的简单使用---实现RPC远程调用