前面介紹過 Thrift 安裝和使用,介紹了Thrift服務的發布和客戶端調用,可以查看我之前的文章:https://www.cnblogs.com/zhangweizhong/category/1006119.html
但是,之前介紹的都是單向的客戶端發送消息,服務端接收消息。而客戶端卻得不到服務器的響應。
那如果我們要實現雙向通信(即:客戶端發送請求,服務端處理返回,服務端發送消息,客戶端處理返回)的功能,該怎么實現呢?
其實在不涉及語言平台的制約,WebService或是webapi 就可以實現這種客戶端發起請求,服務端的處理的單向流程。
然而,實際場景中,可能我們的某些業務需求,更需要服務端能夠響應請求並處理數據。下面我通過一個demo案例,介紹下Thrift 是如何實現雙向通信的。
一、安裝Thrift
這里不再贅述,戳這里查看我上篇文章的介紹:https://www.cnblogs.com/zhangweizhong/category/1006119.html
二、編寫Thrift IDL文件
編寫thrift腳本,命名為student.thrift 如下:
service HelloWorldService{ void SayHello(1:string msg); }
生成service 的方法,之前的文章有介紹,這里就不介紹了。
三、編寫服務端代碼
創建HelloThrift.Server 服務端工程,添加HelloWorldBidirectionServer類,HelloWorldBidirectionServer 實現了Iface接口用於接收客戶端消息,並有一個客戶端傳輸層對象集合用於記錄所有已連接的客戶端。
public class HelloWorldBidirectionServer : HelloWorldBidirectionService.Iface { public void Run(int port) { try { TServerTransport transport = new TServerSocket(port); TTransportFactory transportFac = new TTransportFactory(); TProtocolFactory inputProtocolFactory = new TBinaryProtocol.Factory(); TThreadPoolServer server = new TThreadPoolServer(getProcessorFactory(), transport, transportFac, inputProtocolFactory); server.Serve(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public static List<TTransport> TransportCollection = new List<TTransport>(); public void SayHello(string msg) { Console.WriteLine(string.Format("{0:yyyy/MM/dd hh:mm:ss} 服務端接收到消息: {1}", DateTime.Now, msg)); } public void SayToClient(string msg) { try { foreach (TTransport trans in TransportCollection) { TBinaryProtocol protocol = new TBinaryProtocol(trans); HelloWorldBidirectionService.Client client = new HelloWorldBidirectionService.Client(protocol); //Thread.Sleep(1000); client.SayHello(msg); //Console.WriteLine("發給了客戶端喲"); } } catch (Exception ex) { Console.WriteLine(ex.Message); } } public TProcessorFactory getProcessorFactory() { return new HelloWorldBidirectionProcessor(); } } public class HelloWorldBidirectionProcessor : TProcessorFactory { public TProcessor GetProcessor(TTransport trans, TServer server = null) { if (trans.IsOpen) { HelloWorldBidirectionServer.TransportCollection.Add(trans); Console.WriteLine("客戶端連上。"); } HelloWorldBidirectionServer srv = new HelloWorldBidirectionServer(); return new global::HelloWorldBidirectionService.Processor(srv); } }
四、編寫客戶端代碼
首先創建HelloThrift.Client客戶端項目,添加接收服務端消息的類HelloWorldBidirectionClient,里面只有一個實現Iface接口的方法:
public class HelloWorldBidirectionClient { static HelloWorldBidirectionService.Client client = null; public void ConnectAndListern(int port, string ip = "127.0.0.1") { //Tsocket: TCP/IP Socket接口 TSocket tSocket = new TSocket(ip, port); //消息結構協議 TProtocol protocol = new TBinaryProtocol(tSocket); try { if (client == null) { client = new global::HelloWorldBidirectionService.Client(protocol); tSocket.Open();//建立連接 StartListern(tSocket);//啟動監聽線程 } } catch (Exception ex) { Console.WriteLine(ex.Message); } } public void Say(string msg) { if (client != null) client.SayHello(msg); } void StartListern(TSocket tSocket) { Thread t = new Thread(new ParameterizedThreadStart(Run)); t.Start(tSocket); } public void Run(object tSocket) { HelloWorldBidirectionService.Processor process = new HelloWorldBidirectionService.Processor(new HelloWorldBidirectionFace()); try { while (process.Process(new TBinaryProtocol((TSocket)tSocket), new TBinaryProtocol((TSocket)tSocket))) { Console.WriteLine("消息接收完成,等下一波,阻塞中......"); } } catch (Exception ex) { Console.WriteLine("連接斷開..." + ex.Message); } } } class HelloWorldBidirectionFace : HelloWorldBidirectionService.Iface { public void SayHello(string msg) { Console.WriteLine(string.Format("{0:yyyy/MM/dd hh:mm:ss} 收到服務端響應消息 {1}", DateTime.Now, msg)); } }
實現客戶端,ConnectAndListern方法可以與服務端建立連接,並開啟客戶端端口監聽來自服務端的信息。Say方法可將消息發送至服務端。
五、測試
測試效果如下:
六、最后
1. 關於使用Thrift 構建我們自己的rpc 的方法,這里基本講完了。其他的方法本文就不再演示了,調用起來都是一樣。
2. 后續會簡單討論一下Thrift 框架的通信原理。
3. 源代碼下載,Weiz.Thrift.Shuangxiang.rar