很久就想总结一下Thrift的Cpp lib库的学习情况,但是一直没有狠下心来去写。不是没有时间,就是恐怕理解不透彻。一晃几个月过去了,很多东西已经慢慢遗忘。今天,下定决心重新拾起来,边看边总结。这个故事,就从最有意思的Server端lib开始。这里的Server选用TNonBlockingServer,和他搭配的Transport选用TFrameTransport。这一节主要讲述该类包含的几个辅助类。

TNonblockingServer::TConnection::Task

要注意,Thrift有很多类都包括Task内部类,这里提到的Task类是TConnection的内部类。Task是Server端处理业务逻辑的地方,他继承自Runnable,遵守类似Java的线程模型。因此这个类必须实现run()方法。

run()本质是无限循环,每次循环都会首先调用绑在一起的connection对象的serverEventHandler的processContext方法。这个方法的实现由Thrift的使用者编写。如果实现没有实现这个方法,则跳过这一步骤。

然后,执行processor->process方法。processor是业务执行逻辑的封装,相当于Server的进程。process是调用实际的执行函数,即进程的执行体。执行结果将被序列化,存入输出序列(oprot类似的东西),注意,上文提到的Context也会传入这个执行体中。

最后,调用传输层的peek()。如果传输层使用TFrameTransport,那么其行为是查看读缓冲区里面有没有未处理的帧,如果没有,尝试读取下一个请求帧并且存入读缓冲区。如果依然没有可以读取的东西,返回False。

不论process执行发生了问题(可能不一定是故障,输出序列满也是有可能终止的,真正发生的问题会以异常的方式抛出并捕获),还是peek()得不到新的帧请求,都会跳出循环。循环一旦跳出,则通知Server,实现是调用捆绑的connection对象的notifyIOThread()。该方法的作用在于讲connection对象的指针写入Server的通知管道中。因为整个过程都发生在Server的一个进程中,因此传送指针是有意义的。

TNonblockingServer::TConnection

在TNonBlockingServer中负责处理连接管理,即数据的输入和输出。每个TConnection和一个TNonBlockingIOThread关联,通过其可以获得所在Server的句柄。(但是一个TNonBlockingIOThread可能被多个TConnection关联。)同时记录一个套接字连接的基本信息(sockaddr)。套接字信息存放在内部的TSocket类型的属性中。其他重要属性如下:

a. 输入输出分别为inputTransport和outputTransport属性,他们两个都是TMemoryBuffer的对象指针,实质上就是输入缓冲和输出缓冲。factoryInputTransport_和factoryOutputTransport_是对输入缓冲和输出缓冲的封装。这里,应该是封装为TFrameTransport。

b. 在序列化协议方面,inputProtocol_和outputProtocol_两个属性分别是输入和输出的序列化协议。一般使用TBinaryProtocol。不过,也支持自定义的特殊Transport(没有继承TTransport)的上面架设二进制序列化协议,只是需要传入特定的类型给模板。在这里没有传入类型,可见TNonblockingServer只支持继承TTransport的传输协议,实际上,只支持TFrameTransport。

c. connectionContext。如果创建Server的时候指定了serverEventHandler,那么这里新建connectionContext。实现是调用handler的createContext方法。

d. processor。这个调用比较诡异,他传入了三个参数:inputProtocol_、outputProtocol_还有tSocket_,但是下层调用的时候根本就没有使用这三个参数,而是直接调用的TProcessorFactory的getProcessor。这个方法是个纯虚方法,考察得到该类只有一个派生类,TSingletonProcessorFactory,这里的方法调用时候,根本就没有使用到之前传递的三个参数,而是直接返回的processor_。这是一个单例,可以推测,一个TSingletonProcessorFactory只会拥有一个processor,而且注释要求,所有调用这个方法的线程不得同时出现两个。

构造方法会调用init方法,最终完成所有属性的初始化。除了上面这些属性,比较重要的初始化还有两个,appState<--APP_INIT,socketState<--SOCKET_RECV_FRAMING。这两个State主要是用于TConnection以状态机的方式进行工作预设。

TConnection工作的主要方法,是workSocket和transition。前者是收发数据,后者状态迁移。总之,状态机。

workSocket使用socketState_字段记录3个状态:SOCKET_RECV_FRAMING、SOCKET_RECV、SOCKET_SEND。前两个是接收数据,最后一个是发送数据。前两个的状态迁移顺序是SOCKET_RECV_FRAMING--->SOCKET_RECV。

SOCKET_RECV_FRAMING:接收帧头部。这里也可看出TNonBlockingServer和TFrameTransport是严格绑定在一起的。每个帧分为两个部分:帧头部和帧数据。帧头部以字节为单位标明帧数据的长度。由于整个过程是非阻塞的,每次尽力而为的从网络套接字读取字节,如果头部(目前在0.9.0是4Byte)没有读取结束,存起来,下次调用时候继续。直到获取到完整的帧头部,调用transition。(这里不会多读数据。如果对方断开连接,读取的长度会是0,此时关闭套接字。server规定帧数据部分的长度不得超过256MB,这已经是相当大的一个范围了。如果帧头部指明的长度超过了server预设的最大值,则认为是读出了非法的帧格式,也会关闭套接字。)

SOCKET_RECV:接收帧数据。依然是非阻塞,尽力而为的读取。如果获得了完整的帧数据,调用transition。

SOCKET_SEND:发送帧头部和帧数据。因为是非阻塞,所以要尽力而为的发送,并且不会用for循环。如果期间捕获到EPIPE ECONNRESET ENOTCONN信号,那么抛出异常。如果没有捕获到EWOULDBLOCK或者EAGAIN,但是发送的响应是0字节,那么说明发生了错误,依然抛出异常。

transition使用appState_字段记录状态,基本的状态迁移:

1
2
3
4
5
6
7
8
+--> APP_INIT -----> APP_READ_FRAME_SIZE ---> APP_READ_REQUEST ---+
|                                                                 |
|                                                                 |
|                                                                 |
+------------------- APP_SEND_RESULT    <---  APP_WAIT_TASK <-----+
|                                                   |
|                                                   |
+--------------------oneway-------------------------+

APP_INIT:server最开始的状态。设置读写缓冲区等等基本工作。需要设置等待读的标记位,通过调用setFlags(EV_READ|EV_PERSIST)实现,事件的注册是采用libevent库,回调方法是TConnection::eventHandler,由它调用workSocket方法。

APP_READ_FRAME_SIZE:server已经读到了帧长度。调整读缓冲区大小,以适应帧数据接收。因为残缺的帧数据是没有任何意义的。成倍的增加。最后改变appState_。

APP_READ_REQUEST:server已经获得了完整的帧。将输入缓冲区封装为inputTransport结构,并且重置输入缓冲以待将来使用。此时,满足处理请求的条件了。如果后台不是线程池模式,那么立即执行。否则,构造一个Task结构,丢给server调度。调用setIdle,禁止新的读取消息到来。

APP_WAIT_TASK:server已经处理好这个请求,准备回送返回结果。一般的,计算回送帧大小填充到帧首部,然后调用setFlags(EV_WRITE | EV_PERSIST)声明有数据需要写入套接字。但是,特殊的,如果请求是oneway的,无需回送数据。这时,仅仅需要进入APP_INIT的状态即可。

APP_SEND_RESULT:如果设置了每隔若干请求就重新调整输入输出缓冲区大小,则执行。其实对接口比较少的应用意义并不大,只是之前一直是缓冲不够的时候变大,在这里把缓冲区收回来。然后就是执行APP_INIT逻辑了。

APP_CLOSE_CONNECTION:关闭连接,减少活跃Processor计数。不在基本状态机里面。

其他的方法都比较简单,比如close就是关闭套接字,关闭inputTransport和outputTransport,最后调用server_->returnConnection。倒是有个方法,notifyIOThread,调用ioThread_->notify,先标记在这里。

TNonblockingServer 连接管理相关推荐

  1. http权威指南-http连接管理

    2019独角兽企业重金招聘Python工程师标准>>> HTTP连接管理 浏览器解析URL流程: 浏览器解析出域名: 浏览器查询这个主机名的IP地址: 浏览器获得端口号: 浏览器发起 ...

  2. Oracle RAC 环境下的连接管理(转) --- 防止原文连接失效

    崔华老师的文章!!! 这篇文章详细介绍了Oracle RAC环境下的连接管理,分别介绍了什么是 Connect Time Load Balancing.Runtime Connection Load ...

  3. 5.3.2 TCP连接管理

    5.3.2 TCP连接管理

  4. 5G 信令流程 — 5GC 的连接管理(CM,Connection Management)

    目录 文章目录 目录 5GC 的连接管理 连接管理的状态模型 CM 状态模型 RRC Inactive 状态模型 CM-IDLE 切换到 CM-Connected 流程(RRC.N2 连接建立流程) ...

  5. Oracle RAC 环境下的连接管理

    转自 http://www.oracle.com/technetwork/cn/articles/database-performance/oracle-rac-connection-mgmt-165 ...

  6. plsql objects 过一段时间就会未连接oracle_记一次生产数据库故障排查--连接管理等待事件...

    概述 最近HR数据库比较慢,拿了其中一段时间的awr报告来分析,发现有一个等待事件:connection management call elapsed time,虽然占比不是很大,不过也是有点奇怪, ...

  7. 5G RRC——为NAS层提供连接管理,消息传递等服务; 对接入网的底层协议实体提供参数配置的功能; 负责UE移动性管理相关的测量、控制等功能...

    from:http://www.cnblogs.com/kkdd-2013/p/3868676.html 1 RRC协议功能 为NAS层提供连接管理,消息传递等服务: 对接入网的底层协议实体提供参数配 ...

  8. 【计算机网络】传输层 : TCP 连接管理 ( TCP 连接建立 | 三次握手 | TCP 连接释放 | 四次挥手 )

    文章目录 一.TCP 连接管理 二.TCP 连接建立 三.TCP 连接建立 相关报文段 字段 四.SYN 洪泛攻击 五.TCP 连接释放 一.TCP 连接管理 TCP 传输数据过程 : 建立连接 -& ...

  9. 远程桌面连接管理问题解决方法大全

    我想,人无完人,事物也是.远程桌面连接也不例外,总是会出现各种各样的问题,我们也在解决问 题的路上渐行渐远,此时,要是给我一篇解决问题的大全,我想我会很开心吧,不过网上都是些零零 散散的问题,那我就自 ...

最新文章

  1. LINUX ulimit命令
  2. androidstuido_schooltest_6_media_service
  3. js 浏览器复制功能
  4. mysql8.0.23下载安装详细教程
  5. Win10计算机首次使用时间,如何查看Win10开机运行了多长时间
  6. R学习-小白笔记05
  7. 【专题二】应用号(小程序)开发教程首发第二弹!(0923)
  8. 用友功能传送错误功能加密服务器组件加密服务器错误拒绝访问,用友U8v8.72单机版,登录时系统提示:不能登录到加密服务器。-用友U8...
  9. day023 常用模块02
  10. Netty in action—Netty传输服务
  11. 记第十七次CCF CSP认证
  12. 初学Python选什么版本?
  13. 向日葵远程分辨率过低解决办法
  14. ICE java实现helloworld
  15. 五、完成Teigha.net对CAD文件中的Entity实体进行编辑修改功能,包括字体,样式,颜色,备注XData等属性
  16. AD域组策略安全管理
  17. 跨境电商供应链难点有哪些?
  18. 【nacos】com.alibaba.nacos.shaded.io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
  19. TXT文本数据转换成Excel表格
  20. 农业银行查询开户支行的方法

热门文章

  1. java.io下载_java io 文件下载
  2. Mysql报错130_Mysql报错Forcing close of thread 139 user: 'root'
  3. python图像处理教程_Python基于Tensor FLow的图像处理操作详解
  4. 机器学习笔记十一之降维
  5. WGCNA分析,简单全面的最新教程(在线做,但也需要懂原理)
  6. 诺奖奖金为何119年还没发完?
  7. iheatmapr包:可交互的热图绘制方法
  8. Big Sur更新下载过慢?亲测!满速下载macOS原版系统
  9. P1303 A*B Problem(python3实现)
  10. 小学奥数 7828 最大公约数与最小公倍数 python