thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。
Thrift不仅是一个数据交换格式,它有着一站式跨语言服务的解决方案。因此与Protobuf相比,Thrift更加简单易用直接上手,而且Thrift也支持更多的语言类型。并且因为Thrift与Protobuf相同,都基于二进制数据传输格式,因此与传统的数据交换格式相比,Thrift更快,更小并且没有误解。
综上优点:
与protobuf相比Thrift编码优化不够好,导致编码时间长,编码后体积大。由facebook出品,所以没有文档。虽然提供一站式的服务,但提供的网络层只局限于cs构架,不支持服务器推送,并且有人抱怨网络层的性能也不好。
综上缺点:
如果是简单的RPC,可以使用Thrift快速开发。如果做稳定的服务器开发,则因考虑把其网络层替换。
namespace java com.thrift.demo
service HelloWorldService {
string sayHello(1:string username)
}
thrift-0.10.0.exe --gen java xxx.thrift
import org.apache.thrift.TException;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.server.TServer.*;
import org.apache.thrift.server.TNonblockingServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import com.thrift.demo.HelloWorldService.Iface;
import com.thrift.demo.HelloWorldService.Processor;
public class Server implements Iface{
public static void main(String[] args) throws TTransportException {
startNioServer();
}
//无阻塞Server
public static void startNioServer() throws TTransportException{
//绑定端口
TNonblockingServerSocket socket = new TNonblockingServerSocket(9090);
TNonblockingServer.Args options = new TNonblockingServer.Args(socket);
Server server = new Server();
//注册handler
TProcessor processor = new HelloWorldService.Processor(server);
options.processor(processor);
//设置编解码协议
options.protocolFactory(new TCompactProtocol.Factory());
TServer tserver = new TNonblockingServer(options);
System.out.println("Thrift Server is running at 9090 port");
//启动server
tserver.serve();
}
//简单的阻塞Server
public static void startSimpleServer() throws TTransportException{
//绑定端口
TServerTransport serverTransport = new TServerSocket(9090);
Server server = new Server();
//注册handler
TProcessor processor = new Processor<>((Iface)server);
TServer.Args options = new Args(serverTransport);
//设置编解码协议
options.protocolFactory(new TCompactProtocol.Factory());
options.processor(processor);
TServer tServer = new TSimpleServer(options);
System.out.println("Thrift Server is running at 9090 port");
//启动server
tServer.serve();
}
@Override
public String sayHello(String username) throws TException {
System.out.println("resv:"+username);
return "resv from server : "+username;
}
}
import java.io.IOException;
import org.apache.thrift.TException;
import org.apache.thrift.async.AsyncMethodCallback;
import org.apache.thrift.async.TAsyncClientManager;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TNonblockingServerTransport;
import org.apache.thrift.transport.TNonblockingSocket;
import org.apache.thrift.transport.TNonblockingTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import com.thrift.demo.HelloWorldService.*;
public class client {
public static void main(String[] args) throws TException, IOException, InterruptedException {
startNonblockingClient();
}
//无阻塞,异步回调client
public static void startNonblockingClient() throws IOException, TException, InterruptedException{
TNonblockingTransport transport = new TNonblockingSocket("localhost", 9090);
TProtocol protocol = new TBinaryProtocol(transport);
AsyncClient client ;
TAsyncClientManager clientManager = new TAsyncClientManager();
TProtocolFactory protocolFactory = new TCompactProtocol.Factory();
client = new AsyncClient.Factory(clientManager, protocolFactory).getAsyncClient(transport);
client.sayHello("helloworld", new AsyncMethodCallback() {
@Override
public void onError(Exception exception) {
System.out.println("exception : "+exception);
}
@Override
public void onComplete(String response) {
System.out.println("response : "+response);
}
});
Thread.sleep(1000l);
}
//简单阻塞,同步client
public static void startSimpleClient() throws TException{
TTransport transport = new TSocket("localhost", 9090);
transport.open();
TProtocol protocol = new TCompactProtocol.Factory().getProtocol(transport);
Client client = new Client(protocol);
String resv = client.sayHello("helloworld");
System.out.println("resv:"+resv);
}
}
控制台:
Thrift Server is running at 9090 port
resv:helloworld
生成文件结构如下:
Iface是一个同步的服务端handler接口
Iface是一个异步的服务端handler接口
同步客户端
异步客户端
可见Thrift同时支持同步和异步两种方式的服务端和客户端。并且由前面的例子可以看出Thrift同时也支持NIO和IO。
public class Codec {
private AtomicInteger seqid_ = new AtomicInteger();
TTransport transport = new MTransport();
TProtocol protocol = new TCompactProtocol.Factory().getProtocol(transport);
Map registerMap = new ConcurrentHashMap<>();
public boolean registe(String name,Snapshot ss){
Snapshot res = registerMap.put(name, ss);
if(res == null) return false;
return true;
}
public byte[] encode(MessageInfo info) throws ThriftEncoderException{
try{
protocol.writeMessageBegin(new TMessage(info.getMethodName(), info.getType(), seqid_.incrementAndGet()));
write(info.getArgs(),protocol);
protocol.writeMessageEnd();
byte[] bs = protocol.getTransport().getBuffer();
protocol.getTransport().flush();
return bs;
}catch(Exception e){
throw new ThriftEncoderException(e.getMessage());
}
}
public void decode(byte[] bs) throws TException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
MTransport trans = (MTransport) transport;
trans.put(bs);
TMessage msg = protocol.readMessageBegin();
String MethodName = msg.name;
Snapshot ss = registerMap.get(MethodName);
Object args = ss.args_class.newInstance();
read(args,protocol);
Object res = null ;
//... res = trans(args) 太麻烦了,不写了
ss.getHandler().handle(res);
}
@SuppressWarnings("unused")
private static void write(Object args,TProtocol protocol) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Class extends Object> clazz = args.getClass();
Method m = clazz.getMethod("write", TProtocol.class);
m.invoke(args, protocol);
}
@SuppressWarnings("unused")
private static void read(Object args,TProtocol protocol) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Class extends Object> clazz = args.getClass();
Method m = clazz.getMethod("read", TProtocol.class);
m.invoke(args, protocol);
}
}
class ThriftEncoderException extends Exception{
public ThriftEncoderException(String message) {
super(message);
}
}
class MTransport extends TIOStreamTransport{
MTransport(){
this.outputStream_ = new ByteArrayOutputStream();
}
public void put(byte[] bs){
inputStream_ = new ByteArrayInputStream(bs);
}
@Override
public byte[] getBuffer() {
// TODO Auto-generated method stub
return ((ByteArrayOutputStream)this.outputStream_).toByteArray();
}
@Override
public void flush() throws TTransportException {
super.flush();
}
}
class MessageInfo{
Object args;
//TMessageType
byte type;
String methodName;
public Object getArgs() {
return args;
}
public void setArgs(Object args) {
this.args = args;
}
public byte getType() {
return type;
}
public void setType(byte type) {
this.type = type;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public MessageInfo(Object args, byte type, String methodName) {
super();
this.args = args;
this.type = type;
this.methodName = methodName;
}
}
class Snapshot{
Class args_class;
String methodName;
Class result;
Handler handler;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
public Class getArgs_class() {
return args_class;
}
public void setArgs_class(Class args_class) {
this.args_class = args_class;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Class getResult() {
return result;
}
public void setResult(Class result) {
this.result = result;
}
public Snapshot(Class args_class, String methodName, Class result, Handler handler) {
super();
this.args_class = args_class;
this.methodName = methodName;
this.result = result;
this.handler = handler;
}
}
interface Handler{
T handle(V message);
}
更多关于Thrift的内容请参考http://dongxicheng.org/search-engine/thrift-guide/