thrift是一个软件框架(远程过程调用框架),用来进行可扩展且跨语言的服务的开发,封装了数据传输格式(二进制、json)和网络通信的服务框架,提供多语言(c++, java, python, php, ruby, erlang, perl, haskell, c#, cocoa, javascript, node.js, smalltalk, and ocaml)的网络服务器端和客户端程序组件
适用于搭建大型数据交换及存储的通用工具,对于大型系统中的内部数据传输相对于json和xml无论在性能、传输大小上有明显的优势。
本文以注册服务接口和登录服务器接口为教程,
thrift开发的几个概念:
server 服务模型
handler 数据处理接口
processor 数据处理对象
protocol 数据传输协议
transport 数据传输方式
(1)支持的传输格式
tbinaryprotocol ? 二进制格式.
tcompactprotocol ? 压缩格式
tjsonprotocol ? json格式
tsimplejsonprotocol ?提供json只写协议, 生成的文件很容易通过脚本语言解析。
tdebugprotocol ? 使用易懂的可读的文本格式,以便于debug
(2) 支持的通信方式(数据传输方式)(transport)
tfiletransport:文件(日志)传输类,允许client将文件传给server,允许server将收到的数据写到文件中。
thttptransport:采用http传输协议进行数据传输
tsocket:采用tcp socket进行数据传输
tzlibtransport:压缩后对数据进行传输,或者将收到的数据解压
下面几个类主要是对上面几个类地装饰(采用了装饰模式),以提高传输效率。
tbufferedtransport:对某个transport对象操作的数据进行buffer,即从buffer中读取数据进行传输,或者将数据直接写入buffer
tframedtransport:以frame为单位进行传输,非阻塞式服务中使用。同tbufferedtransport类似,也会对相关数据进行buffer,同时,它支持定长数据发送和接收。
tmemorybuffer:从一个缓冲区中读写数据
(3)支持的服务模型
tsimpleserver ? 简单的单线程服务模型,常用于测试
tthreadedserver - 多线程服务模型,使用阻塞式io,每个请求创建一个线程。
tthreadpoolserver ? 线程池服务模型,使用标准的阻塞式io,预先创建一组线程处理请求。
tnonblockingserver ? 多线程服务模型,使用非阻塞式io(需使用tframedtransport数据传输方式)
处理大量更新的话,主要是在tthreadedserver和tnonblockingserver中进行选择。tnonblockingserver能够使用少量线程处理大量并发连接,但是延迟较高;tthreadedserver的延迟较低。实际中,tthreadedserver的吞吐量可能会比tnonblockingserver高,但是tthreadedserver的cpu占用要比tnonblockingserver高很多。
服务端编写的一般步骤:
1. 创建handler
2. 基于handler创建processor
3. 创建transport(通信方式)
4. 创建protocol方式(设定传输格式)
5. 基于processor, transport和protocol创建server
6. 运行server
客户端编写的一般步骤:
1. 创建transport
2. 创建protocol方式
3. 基于transport和protocol创建client
4. 运行client的方法
上边概述内容参考自:
下面开始正式代码教程
服务描述文件test.thrift,定义了login服务和register
/** * the first thing to know about are types. the available types in thrift are: * * bool boolean, one byte * byte signed byte * i16 signed 16-bit integer * i32 signed 32-bit integer * i64 signed 64-bit integer * double 64-bit floating point value * string string * binary blob (byte array) * map map from one type to another * list ordered list of one type * set set of unique elements of one type * * did you also notice that thrift supports c style comments? */namespace java com.penngonamespace php com.penngostruct user { 1: i64 id, 2: string name, 3: string password}service loginservice{ user login(1:string name, 2:string psw);} service registerservice{ user createuser(1:string name, 2:string psw);}
使用thrift生成对应平台语言代码
thrift -gen java test.thrift
thrift -gen php test.thrift
如果php需要生成服务器端,需求改为thrift -gen php:server test.thrift
java
实现loginserviceimpl.java登录接口业务
import org.apache.thrift.texception;public class loginserviceimpl implements loginservice.iface{ public loginserviceimpl(){ } public user login(string name, string psw) throws texception{ user user = null; if(name.equals(penngo) && psw.equals(123)){ user = new user(); user.setid(1); user.setname(penngo); } return user; }}
实现registerserviceimpl.java注册接口业务
import org.apache.thrift.texception;public class registerserviceimpl implements registerservice.iface{ public registerserviceimpl(){ } public user createuser(string name, string psw) throws texception{ user user = new user(); user.setid(2); user.setname(name); user.setpassword(psw); return user; }}
服务器端java代码
package com.penngo.main;import org.apache.thrift.tmultiplexedprocessor;import org.apache.thrift.server.tserver;import org.apache.thrift.server.tthreadpoolserver;import org.apache.thrift.transport.tserversocket;import org.apache.thrift.transport.ttransportexception;import com.penngo.loginservice;import com.penngo.loginserviceimpl;import com.penngo.registerservice;import com.penngo.registerserviceimpl;public class server { private void start() { try { tserversocket servertransport = new tserversocket(7911); // 用户登录 loginservice.processor loginprocessor = new loginservice.processor( new loginserviceimpl()); // 用户注册 registerservice.processor registerprocessor = new registerservice.processor( new registerserviceimpl()); // factory protfactory = new tbinaryprotocol.factory(true, true); // tserver server = new tthreadpoolserver(new // tthreadpoolserver.args(servertransport) // .processor(loginprocessor)); tmultiplexedprocessor processor = new tmultiplexedprocessor(); processor.registerprocessor(loginservice, loginprocessor); processor.registerprocessor(registerservice, registerprocessor); tserver server = new tthreadpoolserver(new tthreadpoolserver.args( servertransport).processor(processor)); system.out.println(starting server on port 7911 ...); server.serve(); } catch (ttransportexception e) { e.printstacktrace(); } catch (exception e) { e.printstacktrace(); } } public static void main(string args[]) { server srv = new server(); srv.start(); }}
客户端java
package com.penngo.main;import org.apache.thrift.*;import org.apache.thrift.protocol.*;import org.apache.thrift.transport.*;import com.penngo.loginservice;import com.penngo.registerservice;import com.penngo.user;public class client { public static void main(string[] args) { try { ttransport transport = new tsocket(localhost, 7911); tprotocol protocol = new tbinaryprotocol(transport); tmultiplexedprotocol mp1 = new tmultiplexedprotocol(protocol, loginservice); // tprotocol protocol = new tbinaryprotocol(transport); // loginservice.client client = new loginservice.client(protocol); loginservice.client loginclient = new loginservice.client(mp1); tmultiplexedprotocol mp2 = new tmultiplexedprotocol(protocol, registerservice); registerservice.client registerclient = new registerservice.client( mp2); transport.open(); user user = loginclient.login(penngo, 123); if (user != null) { system.out.println(登录成功: + user.getid() + + user.getname()); } else { system.out.println(登录失败); } user user2 = registerclient.createuser(test, 123); if (user2 != null) { system.out.println(创建用户成功: + user2.getid() + + user2.getname()); } else { system.out.println(创建用户失败); } transport.close(); } catch (texception x) { x.printstacktrace(); } }}
客户端php
registernamespace('thrift', __dir__ . '/../../lib');//$loader->registerdefinition('shared', $gen_dir);$loader->registerdefinition('com', $gen_dir);$loader->register();if (php_sapi_name() == 'cli') { ini_set(display_errors, stderr);}use thrift\protocol\tbinaryprotocol;use thrift\protocol\tmultiplexedprotocol;use thrift\transport\tsocket;use thrift\transport\thttpclient;use thrift\transport\tbufferedtransport;use thrift\exception\texception;use com\penngo\registerserviceclient;use com\penngo\loginserviceclient;try { if (array_search('--http', $argv)) { //$socket = new thttpclient('localhost', 8080, '/php/phpserver.php'); } else { $socket = new tsocket('localhost', 7911); } $transport = new tbufferedtransport($socket, 1024, 1024); $protocol = new tbinaryprotocol($transport); $loginprotocol = new tmultiplexedprotocol($protocol, loginservice); $registerprotocol = new tmultiplexedprotocol($protocol, registerservice); $loginclient = new loginserviceclient($loginprotocol); $registerclient = new registerserviceclient($registerprotocol); $transport->open(); $user = $loginclient->login('penngo', '123'); print user===={$user->id} {$user->name} \n; $user = $registerclient->createuser('test', '123456'); print user===={$user->id} {$user->name} \n; $transport->close();} catch (texception $tx) { print 'texception: '.$tx->getmessage().\n; print 'texception: '.$tx->gettraceasstring().\n;}?>