假设读者对thrift有一定了解。

  客户端有时需要非阻塞的去发送请求,给定服务端一个请求,要求其返回一个计算结果。但是客户端不想等待服务端处理完,而是想发送完这个指令后自己去做其他事情,当结果返回时自动的去处理。

  比如举个形象点的例子:饭店的Boss让小弟A把本周店里的欠条收集起来放到自己桌子上,然后又告诉自己的小秘书坐在自己办公室等着小弟A把欠条拿过来,然后统计一下一共有多少,然后Boss自己出去半点事儿。

  Boss相当于client,小弟A相当于server,而小秘书相当于client端的回调函数(callback)。怎么讲呢?Boss不想等待小弟处理完,因为他老人家公务繁忙,还要去干别的呢。于是他把接下来处理欠条的任务托管给了小秘书,于是自己一个人出去了。

  OK,那么我们基本了解了整个工作流程,来看看实现的方法。thrift去实现client异步+回调的方法关键点在于:thrift生成的client中有个send_XXX()和recv_XXX()方法。send_XXX()相当于告知server去处理东西,可以立即返回;而调用recv_XXX就是个阻塞的方法了,直到server返回结果。所以,我们可以在主线程调用完send_XXX()之后,然后另开一个线程去调用send_XXX(),该线程在等到server回复后自动调用callback方法,对结果进行一些处理(当然callback在修改client状态时需要进行同步操作)。这样的模式下,我们可以做很多事情,比如分布式环境下的观察者模式。当然了需要注意的一点就是,各个线程接受到结果的顺序跟请求顺序不一定一样,因为server处理不通请求时间不通或者网络环境的影响都可能导致这种情形。所以如果你对接受这些结果时不是幂等操作时需要注意一下。

thrift脚本:

  1. //只有一个方法,client发送一个消息,server换回一个消息
  2. service TestServ{
  3. string ping(1: string message),
  4. }

server端采用TNBlockingServer实现

  1. #include "TestServ.h"
  2.  
  3. #include <iostream>
  4.  
  5. #include <thrift/protocol/TBinaryProtocol.h>
  6. #include <thrift/server/TNonblockingServer.h>
  7. #include <thrift/transport/TServerSocket.h>
  8. #include <thrift/transport/TBufferTransports.h>
  9. #include <thrift/concurrency/PosixThreadFactory.h>
  10.  
  11. using namespace std;
  12.  
  13. using namespace ::apache::thrift;
  14. using namespace ::apache::thrift::protocol;
  15. using namespace ::apache::thrift::transport;
  16. using namespace ::apache::thrift::server;
  17. using namespace ::apache::thrift::concurrency;
  18.  
  19. using boost::shared_ptr;
  20.  
  21. class TestServHandler : virtual public TestServIf {
  22. public:
  23. TestServHandler() {
  24. // Your initialization goes here
  25. }
  26.  
  27. void ping(std::string& _return, const std::string& message) {
  28. _return = "hello, i am server! ";
  29. sleep();// do something time-consuming/ 这里我们在server端加一些耗时的操作
  30. cout<<"Request from client: "<<message<<endl;
  31. }
  32.  
  33. };
  34.  
  35. int main(int argc, char **argv) {
  36. int port = ;
  37.  
  38. shared_ptr<TestServHandler> handler(new TestServHandler());
  39. shared_ptr<TProcessor> processor(new TestServProcessor(handler));
  40. shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
  41. shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager();
  42. shared_ptr<PosixThreadFactory> threadFactory = shared_ptr<PosixThreadFactory > (new PosixThreadFactory());
  43. threadManager->threadFactory(threadFactory);
  44. threadManager->start();
  45. TNonblockingServer server(processor, protocolFactory, port, threadManager);
  46. server.serve();
  47. return ;
  48. }

client端实现:

  1. #include "TestServ.h"
  2.  
  3. #include <iostream>
  4. #include <thrift/protocol/TBinaryProtocol.h>
  5. #include <thrift/transport/TSocket.h>
  6. #include <thrift/transport/TBufferTransports.h>
  7.  
  8. #include "test_constants.h"
  9.  
  10. using namespace std;
  11. using namespace ::apache::thrift;
  12. using namespace ::apache::thrift::protocol;
  13. using namespace ::apache::thrift::transport;
  14. using boost::shared_ptr;
  15.  
  16. class AsynTestClient;
  17. void * wait_recv(void * parg );
  18. struct PARG {
  19. AsynTestClient * pthis;
  20. string message;
  21. };
  22.  
  23. class AsynTestClient {
  24. private:
  25. unsigned int d_cnt_recv;//< 客户端接受到server响应次数的计数器.
  26.  
  27. pthread_rwlock_t m_cnt_recv;//< 计数器的读写锁.
  28. vector<pthread_t> m_ids;
  29.  
  30. public:
  31. TestServClient * d_client;
  32. void call_back(string & _return){
  33. //输出服务器返回信息并把返回计数加1
  34. cout<<"server msg: "<<_return<<endl;
  35. pthread_rwlock_wrlock( &m_cnt_recv );
  36. d_cnt_recv ++;
  37. pthread_rwlock_unlock( &m_cnt_recv );
  38. }
  39. explicit AsynTestClient(boost::shared_ptr<TProtocol> & protocol){
  40. pthread_rwlock_init( &m_cnt_recv, NULL );
  41. d_cnt_recv = ;
  42. d_client = new TestServClient( protocol );
  43. }
  44.  
  45. ~AsynTestClient(){
  46. delete d_client;
  47. pthread_rwlock_destroy( &m_cnt_recv );
  48. }
  49.  
  50. void asyn_ping( const string & message) {
  51. //发送请求
  52. d_client->send_ping(message);
  53. //初始化每个等待回调线程的参数
  54. PARG * parg = new PARG;
  55. parg->pthis = this;
  56. parg->message = message;
  57. //把新生成的线程id放入全局数组维护
  58. pthread_t m_id;
  59. m_ids.push_back(m_id);
  60. //启动线程,从此只要接受到服务器的返回结果就调用回调函数。
  61. if( != pthread_create( &m_id, NULL, wait_recv, reinterpret_cast< void * > (parg) ) ) {
  62. return;
  63. }
  64. }
  65. };
  66. int main(int argc, char **argv) {
  67.  
  68. boost::shared_ptr<TSocket> socket(new TSocket("localhost", ));
  69. boost::shared_ptr<TTransport> transport(new TFramedTransport(socket));
  70. boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
  71.  
  72. //TestServClient client(protocol);
  73.  
  74. transport->open();
  75. AsynTestClient client(protocol);
  76. string message = "hello, i am client! ";
  77. client.asyn_ping(message);
  78.  
  79. while(true){
  80. sleep();//这里相当于client去做别的事情了
  81. }
  82.  
  83. transport->close();
  84. return ;
  85. }
  86. void * wait_recv(void * parg ) {
  87. PARG * t_parg = reinterpret_cast< PARG * >(parg);//强制转化线程参数
  88. string _return;
  89. t_parg->pthis->d_client->recv_ping(_return);
  90. t_parg->pthis->call_back(_return);
  91. }

  其实大家可以注意到,我并没有使用asyn_ping(const string & message, void(*)call_back(void));这种方式去定义它,这是因为asyn_ping本身可以获取callback函数的指针。回调的本质是任务的托管、时间的复用,也就是说等待结果返回后自动去调用一段代码而已,所以本质上上面就是回调机制。如果你想使用传函数指针的方式,也可以实现出来。

  注意:编译时需要-L$(LIB_DIR) -lthrift -lthriftnb -levent。

【基础】利用thrift实现一个非阻塞带有回调机制的客户端的更多相关文章

  1. java并发编程(8)原子变量和非阻塞的同步机制

    原子变量和非阻塞的同步机制 一.锁的劣势 1.在多线程下:锁的挂起和恢复等过程存在着很大的开销(及时现代的jvm会判断何时使用挂起,何时自旋等待) 2.volatile:轻量级别的同步机制,但是不能用 ...

  2. js多物体多方向缓动动画加带有回调机制

    一.获取一组div元素 var boxs = document.getElementsByTagName('div'); 二.封装获取属性值的函数 function getStyle(dom, att ...

  3. Java基础——NIO(二)非阻塞式网络通信与NIO2新增类库

    一.NIO非阻塞式网络通信 1.阻塞与非阻塞的概念  传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在 ...

  4. Linux非阻塞IO(五)使用poll实现非阻塞的回射服务器客户端

    前面几节我们讨论了非阻塞IO的基本概念.Buffer的设计以及非阻塞connect的实现,现在我们使用它们来完成客户端的编写. 我们在http://www.cnblogs.com/inevermore ...

  5. 爬虫基础--IO多路复用单线程异步非阻塞

    最近一直的学习爬虫  ,进行基础的学习 性能相关 参考 https://www.cnblogs.com/wupeiqi/p/6229292.html # 目标:单线程实现并发HTTP请求 # # so ...

  6. 使用OTP原则构建一个非阻塞的TCP服务器

    http://erlangcentral.org/wiki/index.php/Building_a_Non-blocking_TCP_server_using_OTP_principles CONT ...

  7. 基于委托的C#异步编程的一个小例子 带有回调函数的例子

    我创建的是一个winform测试项目:界面如下: 设置: 下面是代码: using System; using System.Collections.Generic; using System.Com ...

  8. blocking(非阻塞)回调函数

    回调函数不会造成阻塞 function loop() { setTimeout(loop, 0) } loop 死循环 while(true)

  9. nginx学习(二)——基础概念之异步非阻塞

    上面讲了很多关于nginx的进程模型,接下来,我们来看看nginx是如何处理事件的. 有人可能要问了,nginx采用多worker的方式来处理请求,每个worker里面只有一个主线程,那能够处理的并发 ...

随机推荐

  1. android中的广播接收实现总结

    1 首先根据广播应用内接收和应用外接收,分两个类进行管理[1]  LocalBroadcastManager,应用内广播管理类[2]  BroadcastManager  广播管理类(部分应用内,应用 ...

  2. JavaScript Patterns 5.1 Namespace Pattern

    global namespace object // global object var MYAPP = {}; // constructors MYAPP.Parent = function() { ...

  3. Java api 入门教程 之 JAVA的Random类

    在实际的项目开发过程中,经常需要产生一些随机数值,例如网站登录中的校验数字等,或者需要以一定的几率实现某种效果,例如游戏程序中的物品掉落等. 在Java API中,在java.util包中专门提供了一 ...

  4. IntelliJ IDEA14.1中java项目Maven中没有配置JDK时的问题

    在IntelliJ IDEA 14.1中使用在java项目中使用Maven时当没有在Maven中配置JDK编译版本.源码版本时,IDEA将默认的编译版本.源码版本设置为jdk5. 在IDEA中Lang ...

  5. 烂泥:Linux源码包制作RPM包之Apache

    本文由秀依林枫提供友情赞助,首发于烂泥行天下 公司服务器比较多,需要把apache源码包制作成rpm包,然后放到公司内网yum源上进行下载安装.apache的rpm包安装方式比源码安装方式比较快,这能 ...

  6. 烂泥:使用snmpwalk采集设备的OID信息

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 打算开始学习有关监控方面的知识,但是现在很多监控系统都是根据SNMP进行的.而SNMP监控的性能指标很多都是通过snmpwalk采集设备的OID信息得到 ...

  7. Linux 多线程编程

    概念 原来指向main()的线程叫做主线程(main thread) 使用pthread_create()创建出来的线程,叫做子线程(child thread) 主/子线程只有在创建时才有区别, 创建 ...

  8. CentOS 6.3下配置iSCSI网络存储

    一.简介 iSCSI(internet SCSI)技术由IBM公司研究开发,是一个供硬件设备使用的.可以在IP协议的上层运行的SCSI指令集,这种指令集合可以实现在IP网络上运行SCSI协议,使其能够 ...

  9. css3中变形与动画(二)

    css3制作动画的几个属性:变形(transform),过渡(transition)和动画(animation). transform介绍过了.接下来介绍过渡transition. 一.例子 先通过一 ...

  10. 搭建PHP官方框架zend framework 2(LINUX)

    在五花八门的语言里,PHP作为我第一个觉得欣赏的理由,就是它的简单和快捷,因为它封装了许多的常用函数.PHP作为网站中一种算作比较流行的语言,也产生各种优秀的框架.我所接触过的有zend framew ...