在上一篇文章中我们分析了thrift协议的总接口,这个总接口是一个抽象类,它只是声明了读方法和写方法,具体按照什么方式读和写,这需要子类去实现它。这次我们就分析一下利用二进制格式读和写所有的数据。
RPC框架调用使用到的协议主要是发送函数相关的信息到服务器和接受服务器传回的接口。
在介绍TBinaryProtocol之前,我们首先看看怎样通过协议发送相关函数信息的,还是以UserService为例
在UserService中
public void send_getUser() throws org.apache.thrift.TException { //创建一个getUser_agrs对象 getUser_args args = new getUser_args(); //调用TServiceClient中的sendBase()方法,向服务端发送信息 sendBase("getUser", args); }我们在看一下sendBase()方法的具体实现
/** * 客户端通过协议向服务端发送功能信息 oproto_ :TProtocol * @param methodName 功能方法名称,就是thrift文件中定义的方法名称 * @param args TBase封装了读方法和写方法 * @throws TException */ 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(); }从上面的代码中可以看出,不同的具体协议,writeMessageBegin()方法处理格式是不同的,往服务器传递时信息的形式也是不同的。在这段代码上中有一个TBase,这个类封装了读和写的操作
/** * Reads the TObject from the given input protocol. * * @param iprot Input protocol */ public void read(TProtocol iprot) throws TException; /** * Writes the objects out to the protocol * * @param oprot Output protocol */ public void write(TProtocol oprot) throws TException;接下来开始进入今天的主题TBinaryProtocol,看看它是怎样在writeMessageBegin方法中处理数据格式的
/** * * @param message 客户端和服务端传递信息的媒介 * <p></p> * @throws TException */ 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);//写入客户端的标识,这个标识是自动增加的 } }写入版本号的目的就是使客户端和服务端使用相同的协议传输数据,保证数据格式的正确性,接下来看一下具体数据类型的写法
public void writeI32(int i32) throws TException { i32out[0] = (byte)(0xff & (i32 >> 24)); i32out[1] = (byte)(0xff & (i32 >> 16)); i32out[2] = (byte)(0xff & (i32 >> 8)); i32out[3] = (byte)(0xff & (i32)); trans_.write(i32out, 0, 4); }从这也可以看出真正进行网络I/O通信的是通过TTtransport进行的。
读方法
public TMessage readMessageBegin() throws TException { int size = readI32(); if (size < 0) { int version = size & VERSION_MASK; if (version != VERSION_1) { throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in readMessageBegin"); } return new TMessage(readString(), (byte)(size & 0x000000ff), readI32()); } else { if (strictRead_) { throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?"); } return new TMessage(readStringBody(size), readByte(), readI32()); } }
在上一篇文章中我们已经介绍了,每一个具体的协议中都有一个工厂类,这个工厂类都实现了TProtocolFactory