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 像这种畸形文件名在“:”后面的直接被忽略,也就是说当成 *. ...
随机推荐
- js plugin
http://site518.net/javascript-date-handle/ http://developer.51cto.com/art/201212/374902.htm http://e ...
- Jenkins安装入门
这是一次兴奋之旅哈..说不定用得着呢~~~:) 嘿嘿.. 安装很简单,JDK,MAVEN(如果),YUM或RPM包安装JENKINS(因为好像YUM安装好慢,不如RPM下载安装) 参考URL: htt ...
- jQuery validate运作流程以及重复提示错误问题
一,运作流程 jQuery validate要想运作,首先要加载相应的js <script type="text/javascript" src="/js/clas ...
- Access denied for user 'root'@'localhost' (using password:YES) 解决方案
1.打开MySQL目录下的my.ini文件,在文件的最后添加一行“skip-grant-tables”,保存并关闭文件. 2.重启MySQL服务. 3.在命令行中输入“mysql -uroot -p” ...
- [C++关键字] 内置类型
bool, char, short, char16_t (C++11), int, char32_t (C++11), float, long, double,在64位机器上测试各种类型的大小,代码如 ...
- [tools] sublime 使用记录
1. 目录下的文本搜索功能(自带) 1). 把文件夹拖到 sublime 上 2). 在 sublime 上展开要搜索的目录,右击,选择[find in folder] 2. sublime cons ...
- 安装完sql server 后修改计算机名后不能进行发布的订阅的解决办法
由于需要需要配置一个发布订阅,可是一直报告:" sql server 复制需要有实际的服务器名称才能连接到服务器,不支持通过别名.ip地址或其他任何备用名称进行连接.请指定实际的服务器名称“ ...
- Dijkstra算法为什么权值不能为负
Dijkstra算法当中将节点分为已求得最短路径的集合(记为S)和未确定最短路径的个集合(记为U),归入S集合的节点的最短路径及其长度不再变更,如果边上的权值允许为负值,那么有可能出现当与S内某点(记 ...
- OpenReports操作指南
最近要玩OpenReports,但在网上找了一圈,能用的资料少得可怜,所以把最近使用下来,积累的一些技巧记录下来(有部分整合了网上的资源). 备注:以下操作说明基于已做汉化的项目(汉化方案请参考:ht ...
- 在线程中进行读取并写入文件和wenjia
新人求(胸)罩!!! import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException ...