1. 程式人生 > >Thrift總結(四)Thrift實現雙向通訊

Thrift總結(四)Thrift實現雙向通訊

前面介紹過 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

&n