zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Windows下 如何添加开机启动项
    Android在 普通类(非Activity,多数为Adapter) 中 传输数据为空值 解决方法 :在startActivity 用 intent传输数据
    Android 从ImageView中获取Bitmap对象方法
    剑指offer(纪念版)读书笔记【实时更新】
    剑指offer(纪念版) 面试题3:二维数组中的查找
    C++ sizeof 误区 大公司面试题
    51 nod 1521 一维战舰 时间复杂度O(n),同 Codeforces 567D. One-Dimensional Battle Ships 有详细注释
    51nod 1126 求递推序列的第N项 思路:递推模拟,求循环节。详细注释
    51nod 1451 合法三角形 判斜率去重,时间复杂度O(n^2)
    关于JetBrains CLion 激活 (CLion License Activation)的解决办法,带hosts详细修改
  • 原文地址:https://www.cnblogs.com/zhangweizhong/p/11715313.html
Copyright © 2011-2022 走看看