Thrift笔记(三)--Thrift框架通信源码分析
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框架通信源码分析的更多相关文章
- 【原】Spark Rpc通信源码分析
Spark 1.6+推出了以RPCEnv.RPCEndpoint.RPCEndpointRef为核心的新型架构下的RPC通信方式.其具体实现有Akka和Netty两种方式,Akka是基于Scala的A ...
- 通过源码分析Java开源任务调度框架Quartz的主要流程
通过源码分析Java开源任务调度框架Quartz的主要流程 从使用效果.调用链路跟踪.E-R图.循环调度逻辑几个方面分析Quartz. github项目地址: https://github.com/t ...
- 框架-spring源码分析(一)
框架-spring源码分析(一) 参考: https://www.cnblogs.com/heavenyes/p/3933642.html http://www.cnblogs.com/BINGJJF ...
- 框架-springmvc源码分析(一)
框架-springmvc源码分析(一) 参考: http://www.cnblogs.com/heavenyes/p/3905844.html#a1 https://www.cnblogs.com/B ...
- Java8集合框架——LinkedList源码分析
java.util.LinkedList 本文的主要目录结构: 一.LinkedList的特点及与ArrayList的比较 二.LinkedList的内部实现 三.LinkedList添加元素 四.L ...
- 高性能网络I/O框架-netmap源码分析
from:http://blog.chinaunix.net/uid-23629988-id-3594118.html 博主这篇文章写的很好 感觉很有借签意义 值得阅读 高性能网络I/O框架-netm ...
- 框架-springmvc源码分析(二)
框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...
- Spark技术内幕:Client,Master和Worker 通信源码解析
http://blog.csdn.net/anzhsoft/article/details/30802603 Spark的Cluster Manager可以有几种部署模式: Standlone Mes ...
- [dpdk] 熟悉SDK与初步使用 (三)(IP Fragmentation源码分析)
对例子IP Fragmentation的熟悉,使用,以及源码分析. 功能: 该例子的功能有二: 一: 将IP分片? 二: 根据路由表,做包转发. 路由表如下: IP_FRAG: Socket : ad ...
随机推荐
- java 复习总结
java 复习总结 命名方法 创建文件的名称应该和类的名称一致,不然会报错. 类采用首字母大写的方式来命名,如果是多个单词的类名,则每个单词首字母都大写,例如:HelloWorld . 方法采用驼峰命 ...
- UML之时序图详解
原文链接:https://blog.csdn.net/fly_zxy/article/details/80911942 什么是时序图 时序图(Sequence Diagram),又名序列图.循序图,是 ...
- 【问题记录】Python运行报错:can only concatenate str (not "int") to str
自己总是写程序时候用 + 拼接的时候忘记变量类型要一致,如下面 frame_num = "1" for i in range(1, frame_num + 1, 1): self. ...
- explian执行计划
MySQL为我们提供了 explain 关键字来直观的查看一条SQL的执行计划. explain显示了MySQL如何使用索引来处理select语句以及连接表,可以帮助选择更好的索引和写出更优化的查询语 ...
- ionic4 refresh组件位置变更:Ignored attempt to cancel a touchmove event with cancelable=false
io3 中 refresh组件位置可不定: io4 中 须置顶,否则报错,此外complete方法的调用位置改为target属性 参考:https://github.com/ionic-team/io ...
- OC语法
``` int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSString *S= ...
- Loj 6433. 「PKUSC2018」最大前缀和 (状压dp)
题面 Loj 题解 感觉挺难的啊- 状压\(dp\) 首先,有一个性质 对于一个序列的最大前缀和\(\sum_{i=1}^{p} A[i]\) 显然对于每个\(\sum_{i=p+1}^{x}A[i] ...
- 记一次ctf比赛解密题的解决(可逆加密基本破解之暴力破解)
题目是这个样子的: code.txt的内容是这样: 有点吓人木?233333 其实解密之后是这样的: 找到一点安慰没? 好了,废话不多说.讲解一下思路吧. 我们知道base64加密是属于可逆加密的.简 ...
- [转] 使用 Java8 Optional 的正确姿势
[From] https://unmi.cc/proper-ways-of-using-java8-optional/ 我们知道 Java 8 增加了一些很有用的 API, 其中一个就是 Option ...
- C++ GUI Qt4编程(02)-1.2quit
1. 根据C++ GUI Qt4编程(第二版)整理2. 系统:centos7: Qt版本:5.5.13. 程序:quit.cpp #include <QApplication> #inc ...