Thrift 客户端调用RPC的Demo

public static void main(String[] args) throws Exception {
TTransport transport = new TSocket("127.0.0.1", 7912);
TProtocol protocol = new TBinaryProtocol(transport);
// 创建client
com.gxf.thrift.HelloWordService.Client client = new com.gxf.thrift.HelloWordService.Client(protocol);
transport.open(); // 建立连接
// 第一种请求类型
com.gxf.thrift.Request request = new com.gxf.thrift.Request()
.setType(com.gxf.thrift.RequestType.SAY_HELLO).setName("guanxiangfei").setAge(24);
System.out.println(client.doAction(request));
// 第二种请求类型
request.setType(com.gxf.thrift.RequestType.QUERY_TIME).setName("guanxiangfei");
System.out.println(client.doAction(request)); transport.close(); // 请求结束,断开连接
}

这里可以很清楚看到分层设计,以及层层封装。transport, proctol这里网上有人说是用了装饰模式

跟进transport.open()代码

  /**
* Opens the transport for reading/writing.
*
* @throws TTransportException if the transport could not be opened
*/
public abstract void open()
throws TTransportException;

这里是个抽象类TTransport的抽象方法,看下实现类TSocekt实现方法

/**
* Connects the socket, creating a new socket object if necessary.
*/
public void open() throws TTransportException {
if (isOpen()) {
throw new TTransportException(TTransportException.ALREADY_OPEN, "Socket already connected.");
} if (host_ == null || host_.length() == 0) {
throw new TTransportException(TTransportException.NOT_OPEN, "Cannot open null host.");
}
if (port_ <= 0 || port_ > 65535) {
throw new TTransportException(TTransportException.NOT_OPEN, "Invalid port " + port_);
} if (socket_ == null) {
initSocket();
} try {
socket_.connect(new InetSocketAddress(host_, port_), connectTimeout_);
inputStream_ = new BufferedInputStream(socket_.getInputStream(), 1024);
outputStream_ = new BufferedOutputStream(socket_.getOutputStream(), 1024);
} catch (IOException iox) {
close();
throw new TTransportException(TTransportException.NOT_OPEN, iox);
}
}

这里可以看出,用socket建立了连接,为发送序列化数据做准备

继续跟进代码

client.doAction(request)

继续

public String doAction(Request request) throws RequestException, org.apache.thrift.TException
{
send_doAction(request);
return recv_doAction();
}

这里是thrift编译器或者说代码生成器,生成的框架代码

第一个应该是发送序列化数据,第二个方法应该是接收服务端数据。这里分析第一个方法,发送序列化数据。继续跟进代码

public void send_doAction(Request request) throws org.apache.thrift.TException
{
doAction_args args = new doAction_args();
args.setRequest(request);
sendBase("doAction", args);
}

这里request实体被设置到了args里面,继续跟进sendBase

protected void sendBase(String methodName, TBase<?,?> args) throws TException {
sendBase(methodName, args, TMessageType.CALL);
}

继续跟进

private void sendBase(String methodName, TBase<?,?> args, byte type) throws TException {
oprot_.writeMessageBegin(new TMessage(methodName, type, ++seqid_));
args.write(oprot_);
oprot_.writeMessageEnd();
oprot_.getTransport().flush();
}

这是TServerClient.java不是生成代码,是thrift框架代码。这里可以看到RPC方法,args,以及请求类型应该需要被发送给服务端

这里可以看出,先会写一个消息开始的TMessage开始符号, 然后写args,最后写TMessage结束标识,刷新缓存。这应该是thrift发送消息的协议,先发送什么,后发送什么

继续跟进writeMessageBegin()方法

这里跟进的是TBinaryProtocol的实现

public void writeMessageBegin(TMessage message) throws TException {
if (strictWrite_) {
int version = VERSION_1 | message.type;
writeI32(version);
writeString(message.name);
writeI32(message.seqid);
} else {
writeString(message.name);
writeByte(message.type);
writeI32(message.seqid);
}
}

这里可以看出写入消息Begin的内容,version, name, seqid等

继续跟进writeI32(version)看下 一个整型传输的协议

public void writeI32(int i32) throws TException {
inoutTemp[0] = (byte)(0xff & (i32 >> 24));
inoutTemp[1] = (byte)(0xff & (i32 >> 16));
inoutTemp[2] = (byte)(0xff & (i32 >> 8));
inoutTemp[3] = (byte)(0xff & (i32));
trans_.write(inoutTemp, 0, 4);
}

这里可以看出,用了4个byte来存放一个int。然后调用tranport发送。这里Demo里用的应该是TSocket发送。int用4个byte发送应该也是正常的,一个int占4个字节

接着跟进tran_.write()方法。TSocket的父类是TIOStreamTransport。进入TIOStreamTransport

/**
* Writes to the underlying output stream if not null.
*/
public void write(byte[] buf, int off, int len) throws TTransportException {
if (outputStream_ == null) {
throw new TTransportException(TTransportException.NOT_OPEN, "Cannot write to null outputStream");
}
try {
outputStream_.write(buf, off, len);
} catch (IOException iox) {
throw new TTransportException(TTransportException.UNKNOWN, iox);
}
}

这里的outputStream在new TSocket()的时候初始化了,这里也可以看出Demo用的是socket这种阻塞io发送的。当然thrift也支持非阻塞的ChannelSocekt,文件等。

回到写args这一块我还要在看看,好像要跟到生成的代码中。

总结:

1. 底层发送序列化文件用的是socket, channelsocket等

2. thrift有一套自己的协议,如先发送messagebegin标识, int占几个字节等

Thrift笔记(三)--Thrift框架通信源码分析的更多相关文章

  1. 【原】Spark Rpc通信源码分析

    Spark 1.6+推出了以RPCEnv.RPCEndpoint.RPCEndpointRef为核心的新型架构下的RPC通信方式.其具体实现有Akka和Netty两种方式,Akka是基于Scala的A ...

  2. 通过源码分析Java开源任务调度框架Quartz的主要流程

    通过源码分析Java开源任务调度框架Quartz的主要流程 从使用效果.调用链路跟踪.E-R图.循环调度逻辑几个方面分析Quartz. github项目地址: https://github.com/t ...

  3. 框架-spring源码分析(一)

    框架-spring源码分析(一) 参考: https://www.cnblogs.com/heavenyes/p/3933642.html http://www.cnblogs.com/BINGJJF ...

  4. 框架-springmvc源码分析(一)

    框架-springmvc源码分析(一) 参考: http://www.cnblogs.com/heavenyes/p/3905844.html#a1 https://www.cnblogs.com/B ...

  5. Java8集合框架——LinkedList源码分析

    java.util.LinkedList 本文的主要目录结构: 一.LinkedList的特点及与ArrayList的比较 二.LinkedList的内部实现 三.LinkedList添加元素 四.L ...

  6. 高性能网络I/O框架-netmap源码分析

    from:http://blog.chinaunix.net/uid-23629988-id-3594118.html 博主这篇文章写的很好 感觉很有借签意义 值得阅读 高性能网络I/O框架-netm ...

  7. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  8. Spark技术内幕:Client,Master和Worker 通信源码解析

    http://blog.csdn.net/anzhsoft/article/details/30802603 Spark的Cluster Manager可以有几种部署模式: Standlone Mes ...

  9. [dpdk] 熟悉SDK与初步使用 (三)(IP Fragmentation源码分析)

    对例子IP Fragmentation的熟悉,使用,以及源码分析. 功能: 该例子的功能有二: 一: 将IP分片? 二: 根据路由表,做包转发. 路由表如下: IP_FRAG: Socket : ad ...

随机推荐

  1. 题解 P1876 【开灯】

    题目链接 编者说得对 一道很明显的数学题,相信大家小学都做过. 通俗一点,就是找因数为奇数个的数.而这一类的数.明显的是平方数. 所以就是找n以内的平方数. 废话少说,直接上题解. #include& ...

  2. requests库和urllib包对比

    python中有多种库可以用来处理http请求,比如python的原生库:urllib包.requests类库.urllib和urllib2是相互独立的模块,python3.0以上把urllib和ur ...

  3. UML之用例图详解

    原文链接:https://blog.csdn.net/mj_ww/article/details/53020080 UML,即Unified Model Language,统一建模语言.百度百科对他的 ...

  4. 【智能算法】超详细的遗传算法(Genetic Algorithm)解析和TSP求解代码详解

    喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 文章声明 此文章部分资料和代码整合自网上,来源太多已经无法查明出处,如侵犯您的权利,请联系我删除. 00 目录 遗传算法定义 生 ...

  5. SDUT OJ 数据结构实验之二叉树五:层序遍历

    数据结构实验之二叉树五:层序遍历 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descri ...

  6. P2057 [SHOI2007]善意的投票 (最大流)

    题目 P2057 [SHOI2007]善意的投票 解析 网络流的建模都如此巧妙. 我们把同意的意见看做源点\(s\),不同意的意见看做汇点\(t\). 那我们\(s\)连向所有同意的人,\(t\)连向 ...

  7. Java实现二维码生成的方法

    1.支持QRcode.ZXing 二维码生成.解析: package com.thinkgem.jeesite.test; import com.google.zxing.BarcodeFormat; ...

  8. C++_类继承4-访问控制protected

    public和private来控制对类成员的访问. 还存在另外一个访问类别,这种类别用关键字protected表示.protected和private相似,在类外只能用公有类成员来访问protecte ...

  9. bcdedit /copy {current} /d "xxx" 报错,提示找不到系统文件

    步骤: cd c:windows/system32 bcdedit /set {default} osdevice boot bcdedit /set {default} device boot bc ...

  10. React笔记:ref注意事项

    [一]使用ref必须用在[类型式的组件]才起作用,用在[函数式的组件]是无效的. 下面这个例子用在了[函数式的组件]上,所以是无效的: function MyFunctionalComponent() ...