让大家久等了。继续更新thrift序列化的消息体,下面我们一步一步的看一看thrift的rpc是怎么实例化消息体的。

首先我们先准备一个request文件

 namespace java bky
struct TestRequest{
:i32 code;
:string name;
:string data;
}

一个respone文件

 namespace java bky
struct TestRespone{
:i32 code;
:string message;
}

一个service文件

 namespace java bky
include 'TestRequest.thrift'
include 'TestRespone.thrift'
service TestService{
TestRespone.TestRespone testRPC(:TestRequest.TestRequest request);
}

编译文件

生成的文件如下

自己写一个简单的RPC的例子

client

package com.thrift.test;

import bky.TestRequest;
import bky.TestRespone;
import bky.TestService;
import com.thrift.WmCreateAccountRequest;
import com.thrift.WmCreateAccountRespone;
import com.thrift.WmCreateAccountService;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException; import java.util.Random; public class RpcClient { public static final String SERVER_IP = "localhost";
public static final int SERVER_PORT = ;
public static final int TIMEOUT = ; public static void main(String[] args) throws TException { TSocket t = new TSocket ( SERVER_IP, SERVER_PORT, TIMEOUT );
t.open ();
TTransport transport = new TFramedTransport ( t );
TProtocol protocol = new TBinaryProtocol ( transport );
TestRequest request = new TestRequest ();
request.setCode ( );
request.setName ( "博客园" );
request.setData ( "这是我的RPC测试程序" );
TestService.Client client = new TestService.Client ( protocol );
TestRespone result = client.testRPC ( request);
System.out.println ( "Thrify client result =: " + result ); }
}

server

package com.thrift.test;

import bky.TestService;
import bky.TestServiceImpl;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TServer.Args;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException; public class RpcServer { public static final int SERVER_PORT = ; public static void main(String[] a) throws TTransportException { System.out.println("HelloWorld THsHaServer start ...."); TProcessor tprocessor = new TestService.Processor<TestService.Iface> (
new TestServiceImpl ());
TServerSocket serverTransport = new TServerSocket(SERVER_PORT); Args args = new Args (serverTransport);
args.processor(tprocessor);
args.transportFactory(new TFramedTransport.Factory());
args.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new TSimpleServer (args);
server.serve();
}
}

自己的实现类

package bky;

import org.apache.thrift.TException;

public class TestServiceImpl implements TestService.Iface {
@Override
public TestRespone testRPC(TestRequest request) throws TException {
TestRespone respone = new TestRespone();
respone.setCode ( );
respone.setMessage ( "这是服务端的返回示例" );
return respone;
}
}

跟踪thrift的发送源码

 public TestRespone testRPC(TestRequest request) throws org.apache.thrift.TException
{
send_testRPC(request);
return recv_testRPC();
}
protected void sendBase(String methodName, TBase args) throws TException {
oprot_.writeMessageBegin(new TMessage(methodName, TMessageType.CALL, ++seqid_));
args.write(oprot_);
oprot_.writeMessageEnd();
oprot_.getTransport().flush();
}

跟到这里发现其实thrift的发送是分成了4个部分。

1:封装方法信息message,由TProtocol也就是我们上面的TBinaryProtocol发送到TTransport,这里我们的实现是TFrameTransport。

2:将request通过TProtocol序列化,也就是我们上一篇https://www.cnblogs.com/zyl2016/p/10044234.html讲到的东西。

3:把message的结束信息通过TProtocol序列化其实这部是空实现,有特殊需求可以自定义TProtocol重写。

4:通过TTransport将service消息体发送出去

首先我们看writeMessageBegin都干了些什么

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);
}
}

1:默认先写入一个四个字节版本号,区分不同thrift版本,防止thrift8的client和thrift9的server引起的不兼容的问题,然后在写入message.name 也就是方法名称,最后写入seq唯一id,是为了防止client并发引起的问题,所以thrift的client是不支持并发的,因为是一个tcp链路上的传输,所以想允许并发调用接口可以采用apache pool client连接池就可以了。

2:第二步写入request,参照上一篇文章。

3:写入消息结束,这里的TBinaryProtocol实现为空,需要特性化信息的可以进行方法重写。

4:oprot_.getTransport().flush(); 这里通过transport将消息体flush出去,将字节流发送到server。

我们 再看看TTransport发送做了些什么操作,这里我们的实现是TFrameTransport。

private final TByteArrayOutputStream writeBuffer_ =new TByteArrayOutputStream();
public void write(byte[] buf, int off, int len) throws TTransportException {
writeBuffer_.write(buf, off, len);
} @Override
public void flush() throws TTransportException {
byte[] buf = writeBuffer_.get();
int len = writeBuffer_.len();
writeBuffer_.reset(); encodeFrameSize(len, i32buf);
transport_.write(i32buf, , );
transport_.write(buf, , len);
transport_.flush();
}

write方法我们发现其实每次TProtocol write的时候都是将数据流扔到writeBuffer中缓存,等待所有二进制流发送完毕之后统一flush,然后transport先获取到缓存的二进制流,然后通过encodeFrameSize方法获取流的长度转换成4个字节的int数据,然后首先write四个字节长度,然后在wirte后面对应长度的消息体,所以知道长度之后server就可以做对应的拆包操作去调用本地的实现了。咱们本地debug测试一下他发送的字节流数据

首先write一个四个字节的数组,转换成int是81,然后在write消息体,非常清晰简单的消息体,server反解析我会在下一篇文章中去讲解

这里聪明的读者一定会发现,我想自定义协议只需要在transport 的write和read的时候去做一些手脚就可以啦。

在我git上已经https://gitee.com/a1234567891/koalas-rpc 写好了一个完整的RPC例子,客户端采用thrift协议,服务端支持netty和thrift的TThreadedSelectorServer半同步半异步线程模型,支持动态扩容,服务上下线,(权重动态,可用性配置,页面流量统计等),喜欢的小伙伴给个star吧。

更多学习内容请加高级java QQ群:825199617

JAVA RPC (五) 之thrift序列化RPC消息体的更多相关文章

  1. Thrift RPC实战(三) thrift序列化揭秘

    本文主要讲解Thrift的序列化机制, 看看thrift作为数据交换格式是如何工作的? 1.构造应用场景: 1). 首先我们先来定义下thrift的简单结构. 1 2 3 4 5 namespace ...

  2. JAVA RPC (六) 之thrift反序列化RPC消息体

    我们来看一下服务端的简单实现,直接上thrift代码,很直观的来看一看thrift的server到底干了些什么 public boolean process(TProtocol in, TProtoc ...

  3. JAVA RPC (四) 之thrift序列化普通对象

    先简单写一个thrift文件 本地通过thrift编译之后会生成一个java源文件.------编译口令 :thrift -gen java mytestrequest.thrift 编译后的源代码如 ...

  4. JAVA RPC (三) 之thrift序列化协议入门杂谈

    首先抱歉让大家久等了,最近工作的原因,再加上自己维护koalas rpc利用的大部分时间,一直没腾出空来写这篇文章. 先放出来自研的企业级RPC框架源代码地址,上面有使用方式和部署环境说明,说环境部署 ...

  5. JAVA RPC(二)序列化协议杂谈

    序列化和反序列化作为Java里一个较为基础的知识点,大家心里也有那么几句要说的,但我相信很多小伙伴掌握的也就是那么几句而已,如果再深究问一下Java如何实现序列化和反序列化的,就可能不知所措了!遥记当 ...

  6. 开源RPC(gRPC/Thrift)框架性能评测

    海量互联网业务系统只能依赖分布式架构来解决,而分布式开发的基石则是RPC:本文主要针对两个开源的RPC框架(gRPC. Apache Thrift),以及配合GoLang.C++两个开发语言进行性能对 ...

  7. 五分钟快速掌握RPC原理及实现

    随着公司规模的不断扩大,以及业务量的激增,单体应用逐步演化为服务/微服务的架构模式, 服务之间的调用大多采用rpc的方式调用,或者消息队列的方式进行解耦.几乎每个大厂都会创建自己的rpc框架,或者基于 ...

  8. thrift 是rpc协议

    PC(Remote Procedure Call,远程过程调用)是建立在Socket之上的,出于一种类比的愿望,在一台机器上运行的主程序,可以调用另一台机器上准备好的子程序,就像LPC(本地过程调用) ...

  9. RPC简介与Thrift框架

    RPC,全称是remote process call,远程过程调用,简单来讲就是调用部署在另一台服务器上的服务或者被部署在另一台服务器上的服务调用.由于各服务部署在不同机器,服务间的调用免不了网络通信 ...

随机推荐

  1. dubbo服务运行的三种方式

    dubbo服务运行,也就是让生产服务的进程一直启动.如果生产者进程挂掉,也就不存在生产者,消费者不能进行消费. Dubbo服务运行的三种方式如下:1.使用Servlet容器运行(Tomcat.Jett ...

  2. Django之AJAX

    一.预备知识JSON python中的json: json.dumps( )      json.loads( ) JavaScript中的json:JSON.stringify( )       J ...

  3. 【转】浅析Java中的final关键字

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法. ...

  4. Alpha冲刺(10/10)

    目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:冲刺倒计时之10(匆匆而过) 团队部分 后敬甲(组长) 过去两天完成了哪些任务 答辩演练 版本演示视频拍摄 接下来的计划 ...

  5. git remote: HTTP Basic: Access denied Mac 使用Sourcetree 密码输错 再次输入解决方案

    删除下面的key即可

  6. All about Using Burp Suite

    1.how  to use burpsuite I can't thank them enough for allowing us to test web application ,making su ...

  7. 数字滚动特效 NumScroll

    1.使用前先引入jquery2.前端学习群:814798690 下载地址 https://github.com/chaorenzeng/jquery.numscroll.js.git 快速使用 1.引 ...

  8. 精通ArrayList,关于ArrayList你想知道的一切

    目录 精通ArrayList,关于ArrayList你想知道的一切 前言 ArrayList 内部结构,和常用方法实现 实例化方法 添加元素 add()方法 get()方法 移除元素 怎么扩容的 序列 ...

  9. [转] vue从入门到进阶:组件Component详解(六)

    https://www.cnblogs.com/moqiutao/p/8328931.html

  10. beta冲刺1/7

    目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:beta冲刺(1/7) 团队部分 后敬甲(组长) 过去两天完成了哪些任务 团队完成测试答辩 整理博客 复习接口 接下来的 ...