Apache thift 是 facebook开发的一个支持跨语言进程通讯的软件框架.
下面说明node.js 和 C++如何借助于 它进行通讯.
1. 首先, 创建一个 thrift IDL 文件 my.thrift, 如下:
#!/usr/local/bin/thrift --gen cpp
namespace cpp Test
service Something {
i32 ping()
}
ping 是一个 node.js 和 C++ IPC的 接口.
2. 运行命令,创建出 C++文件:
thrift --gen cpp my.thrift
这时,会在当前目录下,生成一个 gen-cpp 目录和一些文件:
$ tree .
.
├── gen-cpp
│ ├── my_constants.cpp
│ ├── my_constants.h
│ ├── my_types.cpp
│ ├── my_types.h
│ ├── Something.cpp
│ ├── Something.h
│ └── Something_server.skeleton.cpp
└── my.thrift
1 directory, 8 files
自动生成了一个 server 文件 Something_server.skeleton.cpp.
运行下面的命令:
cp Something_server.skeleton.cpp Something_server.cpp
server文件内容如下:
$ cat Something_server.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "Something.h"
#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 ::Test;
class SomethingHandler : virtual public SomethingIf {
public:
SomethingHandler() {
// Your initialization goes here
}
int32_t ping() {
// Your implementation goes here
printf("ping, server-side api is called\n");
}
};
int main(int argc, char **argv) {
int port = 9090;
shared_ptr<SomethingHandler> handler(new
SomethingHandler());
shared_ptr<TProcessor> processor(new
SomethingProcessor(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);
server.serve();
return 0;
}
3. client 文件没有自动生成,需要手动写一个:
$ cat Something_client.cpp
#include "Something.h" // As an example
#include <transport/TSocket.h>
#include <transport/TBufferTransports.h>
#include <protocol/TBinaryProtocol.h>
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace Test;
int main(int argc, char **argv) {
boost::shared_ptr<TSocket> socket(new
TSocket("localhost", 9090));
boost::shared_ptr<TTransport> transport(new
TBufferedTransport(socket));
boost::shared_ptr<TProtocol> protocol(new
TBinaryProtocol(transport));
SomethingClient client(protocol);
transport->open();
printf("call ping
........\n");
client.ping();
transport->close();
return 0;
}
5.写一个makefile文件, 如下:
$ cat Makefile
GEN_SRC := Something.cpp my_constants.cpp my_types.cpp
GEN_OBJ := $(patsubst %.cpp,%.o, $(GEN_SRC))
THRIFT_DIR := /usr/local/include/thrift
BOOST_DIR := /usr/local/include
INC := -I$(THRIFT_DIR) -I$(BOOST_DIR)
.PHONY: all clean
all: something_server something_client
%.o: %.cpp
$(CXX) -Wall -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H $(INC) -c $<
-o $@
something_server: Something_server.o $(GEN_OBJ)
$(CXX) $^ -o $@ -L/usr/local/lib -lthrift
something_client: Something_client.o $(GEN_OBJ)
$(CXX) $^ -o $@ -L/usr/local/lib -lthrift
clean:
$(RM) *.o something_server something_client
运行 make,会生成两个可执行文件: something_client 和 something_server
6.测试 C++之间 的 IPC:
$ ./something_server &
[1] 18211
$ ./something_client
call ping ........
ping, server-side api is called
7. 现在配置 node.js:
$ thrift --gen js:node my.thrift
同样,生成一个 gen-nodejs的目录和一些文件:
$ tree gen-nodejs/
gen-nodejs/
├── my_types.js
└── Something.js
0 directories, 2 files
创建一个 client 文件如下:
$ cat client.js
var thrift = require('thrift');
var service = require('./Something.js')
ttypes = require('./my_types');
var connection = thrift.createConnection('localhost', 9090);
connection.on("error", function(err) {
console.error(err);
});
var client = thrift.createClient(service, connection);
client.ping();
connection.end();
执行npm命令,安装 thrift 库:
$ npm install thrift
npm http GET https://registry.npmjs.org/thrift
npm http 304 https://registry.npmjs.org/thrift
thrift@0.7.0 node_modules/thrift
因为, 目前,对于 node.js, TBufferedTransport的模式还不支持,所以要改一下 C++文件,把 TBufferedTransport改成 TframedTransport
改动后的文件如下:
$ cat Something_server.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "Something.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TTransportUtils.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 ::Test;
class SomethingHandler : virtual public SomethingIf {
public:
SomethingHandler() {
// Your initialization goes here
}
int32_t ping() {
// Your implementation goes here
printf("ping, Ha ha, you got it\n");
}
};
int main(int argc, char **argv) {
int port = 9090;
shared_ptr<SomethingHandler> handler(new
SomethingHandler());
shared_ptr<TProcessor> processor(new
SomethingProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new
TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(new
TFramedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new
TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory,
protocolFactory);
printf("starting a server ..........\n");
server.serve();
return 0;
}
8.重新运行 make, 生成新的 server程序.
然后测试
$ ./something_server &
[1] 19532
$ node ./client.js
ping, Ha ha, you got it
P.S.
C++代码部分,参考了
http://wiki.apache.org/thrift
里面的示例代码.这个网址比较有用 ^^