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. 【转】VS2010不能引用System.Data.OracleClient解决方法

    源地址:http://blog.csdn.net/iloli/article/details/8484674

  2. crm录入成绩modelformset组件

    不基于formset组件的普通写法>> views: class RecordScoreView(View): # 录入成绩 def get(self, request,class_stu ...

  3. DataRow[]转DataTable

    DataRow[]有个扩展方法CopyToDataTable()

  4. sqlalchemy orm数据类型验证方法比较

    1.在定义ORM模型时校验 sqlalchemy提供validates函数支持对字段的校验 from sqlalchemy.orm import validates class EmailAddres ...

  5. redis中使用lua脚本

    lua脚本 Lua是一个高效的轻量级脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能 使用脚本的好处 1.减少网络开销,在Lua脚 ...

  6. 【转】IntelliJ Idea取消Could not autowire. No beans of 'xxxx' type found的错误提示

    1.问题描述 在Idea的spring工程里,经常会遇到Could not autowire. No beans of 'xxxx' type found的错误提示.但程序的编译和运行都是没有问题的, ...

  7. tornado 08 数据库-ORM-SQLAlchemy-表关系和简单登录注册

    tornado 08 数据库-ORM-SQLAlchemy-表关系和简单登录注册 引言 #在数据库,所谓表关系,只是人为认为的添加上去的表与表之间的关系,只是逻辑上认为的关系,实际上数据库里面的表之间 ...

  8. 2018acm-icpc青岛站心得

    今年总共两场区域赛,一场南京,一场青岛.南京场队伍真正开始磨合,虽然最后还是铜牌,但是和银牌队伍其实只差一个计算几何的板子的问题.而鉴于南京的教训,所以在准备青岛站的时候,我准备了非常多的模板,还和派 ...

  9. [转] Angular 4.0 内置指令全攻略

    [From] https://segmentfault.com/a/1190000010416792 简书链接 在这篇文章中,我们将分别列举每一个内置指令的用法,并提供一个例子作为演示.尽量用最少最简 ...

  10. 一种简单快速的模板解析方法,活用with javascript版

    //一种简单快速的模板解析方法,活用with var parseTpl = function( str, data ) { var tmpl = 'var __p=[];' + 'with(obj|| ...