本文基於Thrift-0.10,使用Python實現服務器端,使用Java實現客戶端,演示了Thrift RPC調用示例。Java客戶端提供兩個字符串參數,Python服務器端計算這兩個字符串的相似度,並返回相似度結果(double類型,范圍[0, 1],0表示不相似,1表示完全相同)
一,環境安裝
開發環境:Windows10,PyCharm2016,Anaconda3,Python3.6
首先安裝python 的thrift包:windows打開Anaconda prompt,輸入:conda install -c anaconda thrift 安裝thrift包。
輸入:conda list 可查看系統中已經安裝了哪些包,及包的版本,如下圖所示:我們安裝的是:thrift-0.10.0

在寫代碼之前,需要先定義一個 .thrift文件,然后使用Thrift Compiler生成相應的Thrift服務需要依賴的“文件”
①定義.thrift文件
namespace py similarityservice namespace java similarityservice service ChatSimilarityService{ double similarity(1:string chat1, 2:string chat2), }
namespace提供了一種組織代碼的方式。其實就是,生成的文件放在:similarityservice這個文件夾下。
由於前面的Python安裝的thrift-0.10,因此在官網上下載:thrift-0.10.exe,將它放在與 .thrift相同的目錄下,cmd切換到該目錄下,執行命令:
.\thrift-0.10.0.exe --gen py chat_similarity.thrift
生成的文件如下,將它們放在合適的python包下,即可供python 服務端程序 import 了。

二,Python服務端實現
pycharm thrift插件支持
可以去pycharm插件官網下載一個thrift插件,安裝好之后,編寫 .thrift 文件能夠自動補全提示。
服務端的實現 主要有以下五方面:(個人理解,可能有錯)
①Handler
服務端業務處理邏輯。這里就是業務代碼,比如 計算兩個字符串 相似度
②Processor
從Thrift框架 轉移到 業務處理邏輯。因此是RPC調用,客戶端要把 參數發送給服務端,而這一切由Thrift封裝起來了,由Processor將收到的“數據”轉交給業務邏輯去處理
③Protocol
數據的序列化與反序列化。客戶端提供的是“字符串”,而數據傳輸是一個個的字節,因此會用到序列化與反序列化。
④Transport
傳輸層的數據傳輸。
⑤TServer
服務端的類型。服務器以何種方式來處理客戶端請求,比如,一次Client請求創建一個新線程呢?還是使用線程池?……可參考:阻塞通信之Socket編程
TSimpleServer —— 單線程服務器端使用標准的阻塞式 I/O
TThreadPoolServer —— 多線程服務器端使用標准的阻塞式 I/O
TNonblockingServer —— 多線程服務器端使用非阻塞式 I/O
把上面生成的thrift文件復制到 thrift_service包下,如下圖:

整個python 服務端的完整代碼如下:
1 from thrift.protocol import TBinaryProtocol 2 from thrift.server import TServer 3 from thrift.transport import TSocket, TTransport 4 5 from text.thrift_service.similarityservice import ChatSimilarityService 6 7 from difflib import SequenceMatcher 8 from pypinyin import pinyin 9 import zhon 10 import pypinyin 11 from zhon.hanzi import punctuation 12 import re 13 14 __HOST = '127.0.0.1' 15 __PORT = 9090 16 17 18 def similar_num(list1, list2): 19 return len(set(list1).intersection(list2)) 20 21 22 def similar_ration(str1, str2): 23 return SequenceMatcher(lambda x: x == ' ', str1, str2).ratio() 24 25 class SimilarityHandler(ChatSimilarityService.Iface): 26 def __init__(self): 27 self.log={} 28 def ping(selfs): 29 print('ping') 30 31 def similarity(self, chat1, chat2): 32 #去掉中文字符串中的特殊標點符號 33 list1 = re.findall('[^{}]'.format(zhon.hanzi.punctuation), chat1) 34 list2 = re.findall('[^{}]'.format(zhon.hanzi.punctuation), chat2) 35 36 #將標點符號轉換成拼音 37 pinyin1 = pinyin(list1, style=pypinyin.STYLE_NORMAL) 38 pinyin2 = pinyin(list2, style=pypinyin.STYLE_NORMAL) 39 40 #將所有的拼音統一保存到 單個list 中 41 pinyin_list1 = [word[0] for word in pinyin1] 42 pinyin_list2 = [word[0] for word in pinyin2] 43 44 #計算 list 中元素相同的個數 45 result1 = similar_num(pinyin_list1, pinyin_list2) 46 47 #list convert to string 48 str1_pinyin = ''.join(pinyin_list1) 49 str2_pinyin = ''.join(pinyin_list2) 50 #計算字符串的相似度 51 result2 = similar_ration(str1_pinyin, str2_pinyin) 52 53 print('ratio:{}, nums:{}'.format(result2, result1)) 54 return result2 55 56 57 if __name__ == '__main__': 58 handler = SimilarityHandler() 59 processor = ChatSimilarityService.Processor(handler) 60 transport = TSocket.TServerSocket(host=__HOST, port=__PORT) 61 tfactory = TTransport.TBufferedTransportFactory() 62 pfactory = TBinaryProtocol.TBinaryProtocolFactory() 63 64 server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory) 65 66 print('Starting the server') 67 server.serve() 68 print('done')
這里簡單地介紹下實現思路:
①使用python 的 zhon 包過濾掉中文中出現的標點符號等特殊字符
②python的 pypinyin 包 將中文轉換成字符串(其實也可以直接比較中文字符串的相似度,但我這里轉換成了拼音,就相當於比較英文字符串了)
③使用python 的 difflib 包中的SequenceMatcher 類來計算兩個字符串之間的相似度
三,Java客戶端實現
①在maven工程的pom.xml中添加thrift依賴。這里的libthrift版本、windows10下載的thrift compiler版本(thrift-0.10.0.exe),還有 python的 thrift包的版本 最好保持一致。
<!-- https://mvnrepository.com/artifact/org.apache.thrift/libthrift --> <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.10.0</version> </dependency>
②cmd命令行執行:.\thrift-0.10.0.exe --gen java chat_similarity.thrift 生成 ChatSimilarityService.java 文件,Java 客戶端代碼需要依賴它。

整個Java Client的代碼如下:
1 import thrift.similarityservice.ChatSimilarityService; 2 import org.apache.thrift.TException; 3 import org.apache.thrift.protocol.TBinaryProtocol; 4 import org.apache.thrift.protocol.TProtocol; 5 import org.apache.thrift.transport.TSocket; 6 import org.apache.thrift.transport.TTransport; 7 8 /** 9 * Created by Administrator on 2017/12/20. 10 */ 11 public class SimilarityThriftClient { 12 13 public static void main(String[] args) { 14 try { 15 TTransport transport; 16 transport = new TSocket("127.0.0.1", 9090); 17 transport.open(); 18 19 TProtocol protocol = new TBinaryProtocol(transport); 20 ChatSimilarityService.Client client = new ChatSimilarityService.Client(protocol); 21 perform(client); 22 transport.close(); 23 24 } catch (TException e) { 25 e.printStackTrace(); 26 } 27 } 28 private static void perform(ChatSimilarityService.Client client)throws TException { 29 String chat1 = "您好。"; 30 String chat2 = "你好"; 31 double ratio = client.similarity(chat1, chat2); 32 System.out.println(ratio); 33 } 34 }
四,總結
本文介紹了一個簡單的 Python Server、Java Client的Thrift服務調用示例。關於Thrift可參考:
