TSimpleServer简单实现Tserver,代码如下。

/**
* Simple singlethreaded server for testing.
*
*/
public class TSimpleServer extends TServer { private static final Logger LOGGER = LoggerFactory.getLogger(TSimpleServer.class.getName()); private boolean stopped_ = false; public TSimpleServer(AbstractServerArgs args) {
super(args);
} public void serve() {
stopped_ = false;
try {
serverTransport_.listen(); // 开启监听
} catch (TTransportException ttx) {
LOGGER.error("Error occurred during listening.", ttx);
return;
} // Run the preServe event
if (eventHandler_ != null) {
eventHandler_.preServe(); // 前处理切入
} setServing(true); while (!stopped_) {
TTransport client = null;
TProcessor processor = null;
TTransport inputTransport = null;
TTransport outputTransport = null;
TProtocol inputProtocol = null;
TProtocol outputProtocol = null;
ServerContext connectionContext = null;
try {
client = serverTransport_.accept(); // 获得一个client transport
if (client != null) { // 以下代码根据获取的client transport层层封装
processor = processorFactory_.getProcessor(client); // 根据client获取processor
inputTransport = inputTransportFactory_.getTransport(client); // 根据client获取input transport
outputTransport = outputTransportFactory_.getTransport(client); // 根据client获取output transport
inputProtocol = inputProtocolFactory_.getProtocol(inputTransport); // 根据input transport获取input protocol
outputProtocol = outputProtocolFactory_.getProtocol(outputTransport); // 根据output transport获取output protocol
if (eventHandler_ != null) {// 处理前切入eventHandler根据input/output protocol生成connectionContext
connectionContext = eventHandler_.createContext(inputProtocol, outputProtocol);
}
while (true) {// 一直循环处理同一个用户的请求,processor.process永远返回true,只有抛出异常时(即用户端主动关闭连接)才会继续接收下一个用户的请求。
if (eventHandler_ != null) {// 切入eventHandler处理前面生成的connectionContext
eventHandler_.processContext(connectionContext, inputTransport, outputTransport);
}
if(!processor.process(inputProtocol, outputProtocol)) {// 调用processor对input/output protocol进行处理
break;
}
}
}
} catch (TTransportException ttx) {
// Client died, just move on
} catch (TException tx) {
if (!stopped_) {
LOGGER.error("Thrift error occurred during processing of message.", tx);
}
} catch (Exception x) {
if (!stopped_) {
LOGGER.error("Error occurred during processing of message.", x);
}
} if (eventHandler_ != null) {
eventHandler_.deleteContext(connectionContext, inputProtocol, outputProtocol);
} if (inputTransport != null) {
inputTransport.close();
} if (outputTransport != null) {
outputTransport.close();
} }
setServing(false);
} public void stop() {
stopped_ = true;
serverTransport_.interrupt();
}
}

首先,开启监听,然后在处理之前面向切面切入前处理流程 eventHandler_.preServe();最后进入接收处理流程。

处理时关键看第54行processor.process()函数。

TProcessor为一单接口,仅含process方法。其子类thrift不再提供,而是根据用户自定义的thrift IDL文件自动生成。然而thrift提供了一个抽象类TBaseProcessor<I>封装了一些常用的实现,该类实现了TProcessor接口,框架自动生成的Processor都继承了该基类。

TBaseProcessor<I>代码如下:

public abstract class TBaseProcessor<I> implements TProcessor {
private final I iface; // 真正的处理函数实现
private final Map<String,ProcessFunction<I, ? extends TBase>> processMap; protected TBaseProcessor(I iface, Map<String, ProcessFunction<I, ? extends TBase>> processFunctionMap) {
this.iface = iface;
this.processMap = processFunctionMap;
} public Map<String,ProcessFunction<I, ? extends TBase>> getProcessMapView() {
return Collections.unmodifiableMap(processMap);
} @Override
public boolean process(TProtocol in, TProtocol out) throws TException {
TMessage msg = in.readMessageBegin(); // 获取请求信息,主要包含函数名信息。
ProcessFunction fn = processMap.get(msg.name); // 根据函数名信息获取相应的处理函数。
if (fn == null) { // 若没有相关的处理函数,写入异常并返回。
TProtocolUtil.skip(in, TType.STRUCT);
in.readMessageEnd();
TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, "Invalid method name: '"+msg.name+"'");
out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
x.write(out);
out.writeMessageEnd();
out.getTransport().flush();
return true;
}
fn.process(msg.seqid, in, out, iface); // 处理请求
return true;
}
}

ProcessFunction为一抽象类,其子类也是根据IDL自动生成。与IDL中的函数一一对应,为代理处理器。

TBase为IDL中定义的types的基类。T封装了处理函数的参数信息,其子类也是框架根据IDL自动生成。

public abstract class ProcessFunction<I, T extends TBase> {
private final String methodName; private static final Logger LOGGER = LoggerFactory.getLogger(ProcessFunction.class.getName()); public ProcessFunction(String methodName) {
this.methodName = methodName;
} public final void process(int seqid, TProtocol iprot, TProtocol oprot, I iface) throws TException {
T args = getEmptyArgsInstance(); // 获取一个空的参数封装
try {
args.read(iprot); // 从input protol中读取所有参数到args中
} catch (TProtocolException e) {
iprot.readMessageEnd();
TApplicationException x = new TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());
oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
x.write(oprot);
oprot.writeMessageEnd();
oprot.getTransport().flush();
return;
}
iprot.readMessageEnd(); // 读取参数完毕
TBase result = null; try {
result = getResult(iface, args); // 获取处理结果
} catch(Throwable th) {
LOGGER.error("Internal error processing " + getMethodName(), th);
TApplicationException x = new TApplicationException(TApplicationException.INTERNAL_ERROR,
"Internal error processing " + getMethodName());
oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
x.write(oprot);
oprot.writeMessageEnd();
oprot.getTransport().flush();
return;
} if(!isOneway()) {// true表示单向操作不许要返回信息,即函数为void类型。false表示需要返回值,则启用output protol写入结果。
oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.REPLY, seqid));
result.write(oprot);
oprot.writeMessageEnd();
oprot.getTransport().flush();
}
} protected abstract boolean isOneway(); public abstract TBase getResult(I iface, T args) throws TException; public abstract T getEmptyArgsInstance(); public String getMethodName() {
return methodName;
}
}

到此为止,基本了解了libthrift的大致框架。在处理函数中主要是与protocol打交道,protocol又是根据input/output transport生成,而input/output transport又是根据client transport生成。总形成三层结构,底层是client transport由server transport的accept函数获得,中层是input/output transport ,顶层是input/output protocol。然而三层之间并不是完全透明不可见的,典型如oprot.getTransport().flush() 对上层暴露了底层,也无伤大雅。

下节介绍protocol以及transport。

libthrift0.9.0解析(二)之TSimpleServer的更多相关文章

  1. libthrift0.9.0解析(四)之TThreadPoolServer&ServerContext

    TThreadPoolServer直接继承自TServer,实现类serve和stop操作. 在serve中可以接受多个连接,每个连接单独开一个线程进行处理,在每个线程中,按顺序处理该线程所绑定连接的 ...

  2. libthrift0.9.0解析(三)之TProtocol&TTransport

       以上是transport和protocol的类图和结构图. transport封装了底层的传输通道,主要有read/write.open/close等基本的读写方法,而且都是对于二进制数据. p ...

  3. libthrift0.9.0解析(五)之TNonblockingServer&THsHaServer

    本文是一边看代码一边写的,是真随笔,随看随下笔. 看TNonblockingServer,先看其父类AbstractNonblockingServer.一般来说,父类封装的都是通用的东西,具体的底层实 ...

  4. libthrift0.9.0解析(一)之TServer

    TServer 属性serverTransport 为TServerTransport类型,类图如下: 构造函数,简单根据args设置几个成员,大部分是工厂类: protected TServer(A ...

  5. Fixflow引擎解析(二)(模型) - BPMN2.0读写

    Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...

  6. C#使用zxing,zbar,thoughtworkQRcode解析二维码,附源代码

    最近做项目需要解析二维码图片,找了一大圈,发现没有人去整理下开源的几个库案例,花了点时间 做了zxing,zbar和thoughtworkqrcode解析二维码案例,希望大家有帮助. zxing是谷歌 ...

  7. Java生成与解析二维码

    1.下载支持二维码的jar包qrcode.jar和qrcode_swetake.jar, 其中qrcode_swetake.jar用于生成二维码,rcode.jar用于解析二维码,jar包下载地址(免 ...

  8. java 生成和解析二维码

    public class QRCode { /** * 解析二维码(QRCode) * @param imgPath * @return */ public static String decoder ...

  9. java代码生成二维码以及解析二维码

    package com.test; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedI ...

随机推荐

  1. C# ORM—Entity Framework 之Database first(数据库优先)&Model First(模型优先)(一)

    一.什么是Entity Framework 1.1 实体框架(EF)是一个对象关系映射器,使.NET开发人员使用特定于域的对象与关系数据.它消除了需要开发人员通常需要编写的大部分数据访问代码.简化了原 ...

  2. SQLSERVER一个比较不错的分页存储过程p_splitpage

    CREATE procedure p_splitpage @sql nvarchar(4000), --要执行的sql语句 @page int=1, --要显示的页码 @pageSize int, - ...

  3. EMV规范 ---ISO7816 T=0协议的时间特性

    复位应答期间: 字符间的时间间隔最小是12etu,最大是9600etu,但整个ATR不得超过19200etu(TS的起始沿到最后一个字符的起始沿 从卡片发出的连续字符其最小时间间隔为12etu,但是终 ...

  4. C51指针小结

    一. 指针变量的定义 指针变量定义与一般变量的定义类似,其形式如下: 数据类型 [存储器类型1] * [存储器类型2] 标识符: [存储器类型1] 表示被定义为基于存储器的指针.无此选项时,被定义为一 ...

  5. 7.4.1 Dumping Data in SQL Format with mysqldump

    7.4 Using mysqldump for Backups 使用mysqldump 用于备份: 7.4.1 Dumping Data in SQL Format with mysqldump 7. ...

  6. COJ 0581 4022农夫喂牛

    4022农夫喂牛 难度级别:D: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 农夫老张养了N头牛,编号分别从1到N.现在,它们要“用餐”,按 ...

  7. (转载)偏序集的Dilworth定理学习

    导弹拦截是一个经典问题:求一个序列的最长不上升子序列,以及求能最少划分成几组不上升子序列.第一问是经典动态规划,第二问直接的方法是最小路径覆盖, 但是二分图匹配的复杂度较高,我们可以将其转化成求最长上 ...

  8. P2P风险淮安样本:5000万连锁漩涡牵出银行内案

    春节后第一个工作周,来自南京的投资人李宏(化名)频繁游走于两个维权群,因为在江苏淮安的网贷平台投资经历,他结识了136名P2P投资人. 在他们的QQ群里,每个投资人的备注均为网名+投资额,如他自己的“ ...

  9. “/”应用程序中的服务器错误。 / c:\windows\temp目录权限设置

    说明: 1 对该目录的权限是ASP.net生成编译运行的临时文件需要,ASP不需要这个目录是因为ASP的脚本代码是解释执行. 2 Windows2003默认的设置是可以正常运行ASP.net的,造成问 ...

  10. python模块管理

    参考python的模块管理,请看如下 http://blog.sina.com.cn/s/blog_90bc5fc6010159e0.html http://hi.baidu.com/billsche ...