Apache thrift RPC 雙向通訊,apachethrift
在上一篇介紹Apache thrift 安裝和使用,寫了一個簡單的demo,講解thrift服務的發布和用戶端調用,但只是單向的用戶端發送訊息,服務端接收訊息。而用戶端卻得不到伺服器的響應。
在不涉及語言平台的制約,WebService可勝任做這些服務端的處理。
基於大部分業務需求,更需要服務端能夠響應處理資料。下面我通過一個demo案例,介紹下Apache thrift 雙向通訊的使用。
一.首先我們還是需要安裝好Apache thrift。這裡不再贅述,戳這裡查看我上篇文章的介紹:http://www.cnblogs.com/sumingk/articles/6073105.html
二.其次準備好thrift 所需的jar包:
三.建立一個Java web項目,編寫thrift指令碼,命名為student.thrift 如下:
namespace java com.zhj.studenttypedef i32 int typedef i16 shorttypedef i64 long//Student Entitystruct Student { 1: string name} service Zthrift { oneway void send(1:Student msg)}
四.執行student.thrift 檔案,thrift --gen java student.thrift (該檔案我還是放在c盤根目錄下執行),隨後生產gen-java檔案,如下:
五.將新產生的兩檔案拷入項目中,其中Student.java 是實體類,Zthrift.java是產生的類。
六.編寫thrift服務端類。
package com.zhj.server;import org.apache.thrift.TException;import org.apache.thrift.TProcessor;import org.apache.thrift.TProcessorFactory;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.server.TThreadPoolServer;import org.apache.thrift.transport.TServerSocket;import org.apache.thrift.transport.TTransport;import org.apache.thrift.transport.TTransportException;import com.zhj.student.Student;import com.zhj.student.Zthrift;import com.zhj.student.Zthrift.Iface;public class ZServer { public static void main(String[] args){ try { TServerSocket tServerSocket=new TServerSocket(9999); TThreadPoolServer.Args targs=new TThreadPoolServer.Args(tServerSocket); TBinaryProtocol.Factory factory=new TBinaryProtocol.Factory(); //擷取processFactory TProcessorFactory tProcessorFactory= getProcessorFactory(); targs.protocolFactory(factory); targs.processorFactory(tProcessorFactory); TThreadPoolServer tThreadPoolServer=new TThreadPoolServer(targs); System.out.println("start server..."); tThreadPoolServer.serve(); } catch (TTransportException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 內部類擷取 getProcessorFactory * @return */ public static int tt= 0; public static TProcessorFactory getProcessorFactory(){ TProcessorFactory tProcessorFactory=new TProcessorFactory(null){ public TProcessor getProcessor(final TTransport tTransport){ Thread thread = new Thread(new Runnable() { @Override public void run() { try { System.out.println("服務端休眠5秒後,執行響應......"); //延時五秒回複(順延強制給用戶端發送訊息) Thread.sleep(5000); tt +=100; System.out.println("延時五秒回複時,tt = " +tt); //這裡可以把client提取作為成員變數來多次使用 Zthrift.Client client = new Zthrift.Client(new TBinaryProtocol(tTransport)); //給用戶端響應訊息 client.send(new Student("....test")); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); thread.start(); return new Zthrift.Processor<Iface>(new Iface() { @Override public void send(Student msg) throws TException { // TODO Auto-generated method stub tt+=10; System.out.println("接收用戶端訊息時,tt = " +tt); //接受用戶端訊息 System.out.println("....."+msg.toString()); } }); } }; return tProcessorFactory; }}
此處,內部類使用比較頻繁,閱讀會有些困難。Zthrift,Processor構造方法需要傳入一個Iface 介面,該介面有一個接收用戶端的方法send(), msg 是一個Student對象。
七.實現的用戶端調用。如下:
package com.zhj.client;import org.apache.thrift.TException;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.transport.TSocket;import org.apache.thrift.transport.TTransportException;import com.zhj.student.Student;import com.zhj.student.Zthrift.Iface;import com.zhj.student.Zthrift;public class ZClient { public static void main(String[]args){ final TSocket tSocket=new TSocket("127.0.0.1",9999); Zthrift.Client client=new Zthrift.Client(new TBinaryProtocol(tSocket)); try { tSocket.open(); runMethod(tSocket); //向服務端發送訊息 client.send(new Student("小明1")); } catch (TTransportException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void runMethod(final TSocket tSocket){ Thread thread = new Thread(new Runnable() { @Override public void run() { Zthrift.Processor<Iface> mp = new Zthrift.Processor<Zthrift.Iface>(new Iface() { @Override public void send(Student msg) throws TException { // TODO Auto-generated method stub Long start = System.currentTimeMillis(); try { while(true){ //具體接收時間待定 if((System.currentTimeMillis()-start)>0.1*60*1000){ System.out.println("響應訊息逾時..."); break; } else { System.out.println("收到服務端響應訊息: "+msg); } //休眠兩秒 Thread.sleep(2000L); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); try { while(mp.process(new TBinaryProtocol(tSocket), new TBinaryProtocol(tSocket))){ //阻塞式方法,不需要內容 System.out.println("走阻塞式方法"); //關閉tScoket // tSocket.close(); } } catch (TException e) { System.out.println("串連已斷開..."); e.printStackTrace(); } } }); thread.start(); }}
在這裡,我加入了一個逾時響應的死迴圈,用於接收服務端返回的訊息,控制台可以查看服務端給的響應訊息。
八.運行服務端和用戶端main方法,控制台列印如下:
代碼閱讀有些困難,有困難或不合理之處,請小夥伴指出。Thank you!