RPC即遠端過程調用,适用于叢集管理,叢集節點就是RPCServer,而我們發起遠端調用的web伺服器就是RPCClient。是以是少數rpcClient(可能一個)對多個RPCServer(叢集節點)。

rpc_client rpc_server_address command
比如
./ssan_client 192.168.1.1 vmstat
希望這條指令的遠端執行(在RPCServer上)的結果直接在直接輸出到web伺服器(RPCClient)。可以先看一個執行效果。
那麼要做到這樣一種效果,需要借助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,是為了解決這個錯誤
安裝完成之後
編寫thrift檔案
編寫ssan.thrift檔案
namespace cpp ssan
service SSANAgent {
string run(1:string command)
}
這裡定義了一個接口方法run,接收一個string類型的參數,表示要執行的指令
使用thrift生成
thrift -r --gen cpp ssan.thrift
生成的源代碼主要在SSANAgent.cpp中,可以翻看SSANAgent.h的定義。
可以看到,我們隻需要寫一個類繼承這個類,重寫run方法,在run方法裡實作業務,并且可以看到它幫我們添加了一個參數,這個參數用來做什麼呢?用來傳回結果。Thrift連這事都幫你準備好了
編寫rpcServer
thrift已經為我們生成了server的模闆
cp SSANAgent_server.skeleton.cpp SSANServer.cpp
之前定義的接口方法也主要定義在這個類裡
修改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
連結後運作出現這個錯誤
這個檔案其實已經存在了,不過在目錄/usr/local/lib/下,而程式運作時再/usr/lib下搜尋動态庫檔案,是以建立一個軟連結
ln -s /usr/local/lib/libthrift-1.0.0-dev.so /usr/lib/libthrift-1.0.0-dev.so
再執行就成功啟動了
編寫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,可以看到這樣的效果
至此,RPCServer和RPCClient都已經生成了,下一步就是解決靜态編譯的問題。因為時間有限,這個将會在下一篇部落格中PHP對RPC服務的調用封裝中寫出