libthrift0.9.0解析(五)之TNonblockingServer&THsHaServer
本文是一边看代码一边写的,是真随笔,随看随下笔。
看TNonblockingServer,先看其父类AbstractNonblockingServer。一般来说,父类封装的都是通用的东西,具体的底层实现方式交由子类来实现。因此抽象类一般会作为两层之间的交点所在,父类在上层,子类在下层。先看父类,再看子类,先看高层,再看低层,先看框架再忽略底层细节,遇到一些细节非常想看想深入进去时,也会忍住不看,待到上层了解完毕之后,再回过头来看。必要先在头脑中形成一个坐标系,然后再往其中安放具体物件。不知这样对也不对【注:此方法不一定好,最好是单步调试跟入代码。11.11】。
AbstractNonblockingServer父类为Tserver,实现了serve方法:
public void serve() {
// start any IO threads
if (!startThreads()) {
return;
}
// start listening, or exit
if (!startListening()) {
return;
}
setServing(true);
// this will block while we serve
waitForShutdown();
setServing(false);
// do a little cleanup
stopListening();
}
startThreads方法开启一个线程,处理所有通道(连接)的所有请求,交由子类实现;startListening方法为通用方法,执行监听:serverTransport_.listen()。
看其子类TNonblockingServer中startThreads的实现:利用serverTransport_(必为TNonblockingServerTransport类型)构造一个SelectAcceptThread线程,然后开启。到此为止,服务开启完毕。
下面看SelectAcceptThread的实现,抽象父类为AbstractSelectThread,直接继承自Thread类。
按照上述原则,看AbstractSelectThread的构造函数和run方法。构造函数初始化了一个selector,没有run方法,其它很多方法,略去不看先。接着看子类SelectAcceptThread。
构造函数中把serverTransport注册到selector中,注册事件为accept。run方法主要代码:
while (!stopped_) {
select();
processInterestChanges();
}
看其字面,select处理具体事件,processInterestChanges处理其它一些事务。
在select函数中,用handleAccept、handleRead、handleWrite处理各种事件,具体怎么处理,不用管先。
在processInterestChanges函数中,遍历Set<FrameBuffer>列表selectInterestChanges,对每个FrameBuffer调用其changeSelectInterests方法。ok,这轮完毕。
在handleAccept中,accect一个client,然后client在selector上注册read事件,然后根据client, clientKey生成一个FrameBuffer对象,把该对象绑定到clientKey上。
在handleRead中,取出绑定的FrameBuffer对象buffer,调用buffer的read方法从通道中读取数据,读取完毕后调用requestInvoke方法对该buffer进行处理,怎么处理的?等会儿再看。
在handleWrite中,调用绑定frameBuffer的write方法。
这轮结束,可以看出,其核心逻辑集中在FrameBuffer对象中。
看FrameBuffer构造函数,只是对传入的client,clientKey,selectorThread进行保存;
上轮的requestInvoke方法调用的是其invoke()方法,在invoke方法中,调用Processor对请求进行处理,处理完毕后调用responseReady方法和requestSelectInterestChange方法通知处理完毕,可进行下一步操作。
以下是responseReady的注释:
/**
* After the processor has processed the invocation, whatever thread is
* managing invocations should call this method on this FrameBuffer so we
* know it's time to start trying to write again. Also, if it turns out that
* there actually isn't any data in the response buffer, we'll skip trying
* to write and instead go back to reading.
*/
对注释的注释,也即当请求处理完毕后,检查 frameBuffer中的response,若有返回值,把frameBuffer当前状态置为准备写的状态(AWAITING_REGISTER_WRITE),否则,置为读的状态,可以继续读取下一条。
下面看changeSelectInterests方法,还是直接上代码比较明了:
/**
* Give this FrameBuffer a chance to set its interest to write, once data
* has come in.
*/
public void changeSelectInterests() {
if (state_ == FrameBufferState.AWAITING_REGISTER_WRITE) {
// set the OP_WRITE interest
selectionKey_.interestOps(SelectionKey.OP_WRITE);
state_ = FrameBufferState.WRITING;
} else if (state_ == FrameBufferState.AWAITING_REGISTER_READ) {
prepareRead();
} else if (state_ == FrameBufferState.AWAITING_CLOSE) {
close();
selectionKey_.cancel();
} else {
LOGGER.error("changeSelectInterest was called, but state is invalid (" + state_ + ")");
}
}
也即判断当前状态,若为准备写,则注册client的写事件,若为读,注册读事件,并提前做好准备。
主要逻辑大概如上,现在让我们注意一下thrift中nonblcokingServer用到的一个特殊的transport==》TFramedTransport。它出现在AbstractNonblockingServerArgs的构造函数中:
public AbstractNonblockingServerArgs(TNonblockingServerTransport transport) {
super(transport);
transportFactory(new TFramedTransport.Factory());
}
在NonblockingServer被构建时传入,在frameBuffer的invoke方法中被使用:
TTransport inTrans = getInputTransport();
TProtocol inProt = inputProtocolFactory_.getProtocol(inTrans);
TProtocol outProt = outputProtocolFactory_.getProtocol(getOutputTransport());
上面代码中的 inTrans和outProt其类型都为TFramedTransport。
它跟其它的transport的区别为“TFramedTransport is a buffered TTransport that ensures a fully read message every time by preceding messages with a 4-byte frame size.” 即每个数据包头4个byte,即一个int,指明该包(frame)内容的大小,每次读写都是以frame为单位读写的。
libthrift0.9.0解析(五)之TNonblockingServer&THsHaServer的更多相关文章
- libthrift0.9.0解析(四)之TThreadPoolServer&ServerContext
TThreadPoolServer直接继承自TServer,实现类serve和stop操作. 在serve中可以接受多个连接,每个连接单独开一个线程进行处理,在每个线程中,按顺序处理该线程所绑定连接的 ...
- libthrift0.9.0解析(三)之TProtocol&TTransport
以上是transport和protocol的类图和结构图. transport封装了底层的传输通道,主要有read/write.open/close等基本的读写方法,而且都是对于二进制数据. p ...
- libthrift0.9.0解析(二)之TSimpleServer
TSimpleServer简单实现Tserver,代码如下. /** * Simple singlethreaded server for testing. * */ public class TSi ...
- libthrift0.9.0解析(一)之TServer
TServer 属性serverTransport 为TServerTransport类型,类图如下: 构造函数,简单根据args设置几个成员,大部分是工厂类: protected TServer(A ...
- C语言文件操作解析(五)之EOF解析(转载)
C语言文件操作解析(五)之EOF解析 在C语言中,有个符号大家都应该很熟悉,那就是EOF(End of File),即文件结束符.但是很多时候对这个理解并不是很清楚,导致在写代码的时候经常出错,特 ...
- dubbo源码解析五 --- 集群容错架构设计与原理分析
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...
- Spring Security 解析(五) —— Spring Security Oauth2 开发
Spring Security 解析(五) -- Spring Security Oauth2 开发 在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决 ...
- Celery 源码解析五: 远程控制管理
今天要聊的话题可能被大家关注得不过,但是对于 Celery 来说确实很有用的功能,曾经我在工作中遇到这类情况,就是我们将所有的任务都放在同一个队列里面,然后有一天突然某个同学的代码写得不对,导致大量的 ...
- IIS6.0解析漏洞
IIS6.0解析漏洞分两种 1.目录解析 以*.asp命名的文件夹里的文件都将会被当成ASP文件执行. 2.文件解析 *.asp;.jpg 像这种畸形文件名在“:”后面的直接被忽略,也就是说当成 *. ...
随机推荐
- Shuffle'm Up
poj3087:http://poj.org/problem?id=3087 题意:题意简化之后的就是:给你两个长度均为c的字符串s1,s2,然后给你一个2*c的串ss,现在每次从s2,中取一个,然后 ...
- linux 发布 qt(更新ld命令的路径依赖)
PATH 错误解决error while loading shared libraries: libXXX.so.X: cannot open shared object file: No such ...
- Mysql 数字类型转换函数
.将Int 转为varchar经常用 concat函数,比如concat(,' .将varchar 转为Int 用 cast(a as signed) a为varchar类型的字符串 总结:类型转换和 ...
- zabbix 参数说明
<pre name="code" class="html">数据采集的工作模式可以分为被动模式(服务器端到客户端采集数据) 主动模式(客户端主动上报 ...
- 【Linux】鸟哥的Linux私房菜基础学习篇整理(三)
1. gzip [-cdtv#] filename:压缩.参数:-c:将压缩的数据输出到屏幕上,可通过数据重定向进行处理:-d:解压缩的参数:-t:可以用来检验一个压缩文件的一致性,查看文件有无错误: ...
- ural-1099-Work Scheduling(裸带花树)
题意: 有N个人,有限对的人可以在一起工作,问最多能有多少对. 分析: 任意图的最大匹配 // File MAXName: 1099.cpp // Author: Zlbing // Created ...
- 【转】BLE 学习记录
原文网址:http://m.blog.csdn.net/blog/chiooo/43985401 BLE 学习记录 ANROID BLE 开发,基于 bluetoothlegatt 分析 mBluet ...
- 图论(网络流):[HNOI 2013]切糕
[HNOI 2013]切糕 第三题:切糕(程序文件名:cake.exe)100 分,运行时限:5s 经过千辛万苦小A 得到了一块切糕,切糕的形状是长方体,小A 打算拦腰将切糕切成两半分给小B.出于美观 ...
- HDOJ(HDU) 2162 Add ‘em(求和)
Problem Description Write a program to determine the summation of several sets of integers. Input Th ...
- Java Spring的 JavaConfig 注解
序 传统spring一般都是基于xml配置的,不过后来新增了许多JavaConfig的注解.特别是springboot,基本都是清一色的java config,不了解一下,还真是不适应.这里备注一下. ...