關(guān)于這個(gè)話題芍瑞,網(wǎng)上有大量的文章;但是配置部分都講得比較混亂皮胡,直接拷來并不能跑通痴颊。
本文以python和java分別作為服務(wù)端/客戶端及其逆形式進(jìn)行了演示,不求甚解屡贺,只求能用蠢棱。
定義好thrift文件,作為C/S的契約[1]
xxx.thrift
注意:以下代碼都是手動(dòng)混淆過的甩栈,僅大致示意寫法泻仙,不保證內(nèi)容正確
namespace java com.x1.x2.x3.x4.x5.gen_java # 注意,如果是為java版本準(zhǔn)備的量没,一定要寫好package
struct MyStruct1{
1:string field1,
2:list<string> field2,
3:optional list<MyStruct1> field3, # 注意java不支持optinal玉转,生成的代碼中只有必選項(xiàng)
}
struct MyStruct2{
1:list<i16> data
}
service MyService{
void f1(1:MyStruct1 s1)
list<MyStruct2> f2(1:string field1, 2:MyStruct1 data)
}
將thrift文件分別編譯成服務(wù)器端語言和客戶端語言
注意:自動(dòng)生成的python代碼中,可能有class A依賴class B殴蹄,而A的代碼卻寫到了同一個(gè)文件中B的下方的情況究抓;這可能是thrift的一個(gè)BUG,手動(dòng)調(diào)整代碼順序即可
mkdir gen_py gen_java # 默認(rèn)名字是用短橫線分隔(gen-py)袭灯,不符合python的包命名要求漩蟆;手動(dòng)改成下劃線
thrift -r --gen py -out gen_py xxx.thrift
thrift -r --gen java -out ../../../../../../ xxx.thrift # 路徑中有x1-x5,就要上6層
實(shí)現(xiàn)服務(wù)端邏輯
注意:
- gen_py和gen_java文件夾的內(nèi)容最好別改動(dòng)妓蛮;它們都只是作為輔助類庫(kù)使用的
- 服務(wù)器端要自己寫一個(gè)Handler類去override指定的方法
- 客戶端只要綁定到指定的端口上調(diào)用即可
python版服務(wù)器端
先用自己的類來繼承IFace怠李,實(shí)現(xiàn)各個(gè)接口
# thrift 相關(guān)的引用
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
from thrift.transport import TSocket, TTransport
# import ... # 邏輯相關(guān)的引用
class MyHandler(MyService.Iface):
def __init__(self):
transport = TSocket.TSocket('hostname', 8095) # 最好用IP,穩(wěn)一點(diǎn)
transport = TTransport.TBufferedTransport(transport)
transport.open() # 注意這一行不能少
protocol = TBinaryProtocol.TBinaryProtocol(transport)
# self.xxx = yyy 之類的初始化,省略 ...
def f1(self, arg1):
pass # ...
然后寫一個(gè)server.py
來包裹handler并控制服務(wù)的起停
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
from thrift.transport import TSocket, TTransport
# sys.path.append('thrift/gen_py') # 可能需要把gen_py加到PYTHONPATH
# import ... # 邏輯相關(guān)的引用
def main():
handler = MyHandler()
processor = MyService.Processor(handler)
transport = TSocket.TServerSocket('10.1.x.x', 8081)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory)
logger.info('---------- starting xxx server over thrift...')
server.serve()
logger.info('---------- shutting down xxx server over thrift...')
if __name__ == '__main__':
main()
java版的服務(wù)器端
同理捺癞,先寫個(gè)Handler類來覆蓋相應(yīng)的method
package com.xxx.xxx.xxx
// import ...
public class MyHandler implements MyService.Iface {
@Override
public synchronized void f1(MyStruct1 arg1) throws TException {
// ...
}
// ...
}
然后寫個(gè)Server類來包裹Handler并控制服務(wù)的起停
package com.x.x.x.xxx
import ... // 邏輯相關(guān)的引用
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
import java.io.IOException;
import java.net.InetSocketAddress;
public class MyServer {
public static void main(String[] args) throws IOException, TTransportException {
MyService.Processor processor = new MyService.Processor(new MyHandler());
TServerSocket serverTransport = new TServerSocket(new InetSocketAddress("1.2.3.4", 1234));
TServer server = new TSimpleServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
System.out.println("Starting server...");
server.serve();
}
}
實(shí)現(xiàn)客戶端邏輯
java版客戶端
先把之前運(yùn)行thrift -r --gen java ...
命令生成的gen_java
文件夾拷進(jìn)來夷蚊,作為一個(gè)package;
然后把Guava等其它各種類庫(kù)寫進(jìn)maven/Gradle髓介。
插一句:如果用到讀寫wav文件的功能惕鼓,可以把wavFile相關(guān)的類庫(kù)[2]下載了拷進(jìn)來。
package com.xxx.yyy;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
// import ...
public class App {
public void work(List<String> arg) {
try {
TTransport transport = new TSocket("1.2.3.4", 1234); // 注意兩邊都盡量用IP唐础,比較穩(wěn)一點(diǎn)
transport.open();
TProtocol protocol = new TBinaryProtocol(transport);
MyService.Client client = new MyService.Client(protocol);
// arg1 = ...
client.f1(arg);
// 多次調(diào)用 client.f2(...)
transport.close();
System.out.println("----- client done");
} catch (TException ex) {
ex.printStackTrace();
} // 更多catch ...
}
public static void main(String[] args) {
App app = new App();
app.work(Lists.newArrayList("arm", "aunt", "autumn"));
}
}
python版的客戶端寫法
from thrift.protocol import TBinaryProtocol
from thrift.transport import TSocket, TTransport
# 可能需要將gen_py加到PYTHONPATH
# import 邏輯相關(guān)的模塊 ...
def main():
transport = TSocket.TSocket('1.2.3.4', 8081)
transport = TTransport.TBufferedTransport(transport)
transport.open()
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = MyService.Client(protocol)
# arg = ...
client.f1(arg)
# 多次調(diào)用 client.f2(...)
print('----- client done')
if __name__ == '__main__':
main()
-
thrift文件寫法參考:http://www.reibang.com/p/0f4113d6ec4b ?
-
Java Wav File IO API:http://www.labbookpages.co.uk/audio/javaWavFiles.html ?