Thrift 序列化示例

IDL如下:

namespace java com.app.thrift.test
service Hello{
    UserMessage tell(1:UserMessage message)
}

struct UserMessage{
    1:i32 userId;
    2:string username;
    3:string message
}

使用thrift-0.10.0.exe 生成相关的java类:

 thrift-0.10.0.exe -gen java Hello.thrift

测试客户端代码:

 TTransport transport = null;
        try {
            transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
            TProtocol protocol = new TBinaryProtocol(transport);
            com.app.thrift.test.hello.Hello.Client client = new Hello.Client(protocol);
            UserMessage message = new UserMessage();
            message.setMessage(" are you come from sy?");
            message.setUserId(1002);
            message.setUsername("user1");

            transport.open();
            UserMessage backMessage =  client.tell(message);
            System.out.println("Thrify client result : " );
            System.out.println("from " + backMessage.getUsername() + "(" + backMessage.getUserId() + "):" + backMessage.getMessage());
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            if (null != transport) {
                transport.close();
            }
        }

服务端代码只是截取报文:

  

 try {
            ServerSocket serverSocket = new ServerSocket(SERVER_PORT);
            Socket socket = serverSocket.accept();
            InputStream is = socket.getInputStream();
            byte [] data = new byte[1024];
            int length = is.read(data);
            FileOutputStream fos = new FileOutputStream(new File("c:\\test.log"));
            while(length>0){
                fos.write(data,0,length);
                length = is.read(data);
            }
            fos.close();
            System.out.println("readFinish");
        }catch (Exception e){
            e.printStackTrace();
        }

数据由TProtocol写入。

TProtocol--协议层(按照协议规定的格式)--》写入--》TTransport--(代表了与另一端服务连接的通道,可如Socket)

(TProtocol 需要内部持有TTransport)

  TProtocol 代码如下:

public abstract class TProtocol {

  /**
   * Transport
   */
  protected TTransport trans_;
  
  /**
   * Writing methods.
   */
 public abstract void writeMessageBegin(TMessage message) throws TException;

  public abstract void writeMessageEnd() throws TException;

  public abstract void writeStructBegin(TStruct struct) throws TException;

  public abstract void writeStructEnd() throws TException;

  public abstract void writeFieldBegin(TField field) throws TException;

  public abstract void writeFieldEnd() throws TException;

  public abstract void writeFieldStop() throws TException;

  public abstract void writeMapBegin(TMap map) throws TException;

  public abstract void writeMapEnd() throws TException;

  public abstract void writeListBegin(TList list) throws TException;

  public abstract void writeListEnd() throws TException;

  public abstract void writeSetBegin(TSet set) throws TException;

  public abstract void writeSetEnd() throws TException;

  public abstract void writeBool(boolean b) throws TException;

  public abstract void writeByte(byte b) throws TException;

  public abstract void writeI16(short i16) throws TException;

  public abstract void writeI32(int i32) throws TException;

  public abstract void writeI64(long i64) throws TException;

  public abstract void writeDouble(double dub) throws TException;

  public abstract void writeString(String str) throws TException;

  public abstract void writeBinary(ByteBuffer buf) throws TException;

  /**
   * Reading methods.
   */

  public abstract TMessage readMessageBegin() throws TException;

  public abstract void readMessageEnd() throws TException;

  public abstract TStruct readStructBegin() throws TException;

  public abstract void readStructEnd() throws TException;

  public abstract TField readFieldBegin() throws TException;

  public abstract void readFieldEnd() throws TException;

  public abstract TMap readMapBegin() throws TException;

  public abstract void readMapEnd() throws TException;

  public abstract TList readListBegin() throws TException;

  public abstract void readListEnd() throws TException;

  public abstract TSet readSetBegin() throws TException;

  public abstract void readSetEnd() throws TException;

  public abstract boolean readBool() throws TException;

  public abstract byte readByte() throws TException;

  public abstract short readI16() throws TException;

  public abstract int readI32() throws TException;

  public abstract long readI64() throws TException;

  public abstract double readDouble() throws TException;

  public abstract String readString() throws TException;

  public abstract ByteBuffer readBinary() throws TException;

  }

得到报文(c:\\test.log),用二进制方式查看:



 解释一下上图中的传输报文内容:(由TBinaryProtocol写入)

1.80 01  00 01

    协议版本号   80 01  00 00 (或操作)  消息类型  01 call    

    消息类型为:01 对应 call--调用

    其它消息类型为:

   

public final class TMessageType {
  public static final byte CALL  = 1;
  public static final byte REPLY = 2;
  public static final byte EXCEPTION = 3;
  public static final byte ONEWAY = 4;
}

2.  00 00 00 04

   方法名称长度,int型:4个bit ,值=4,即之后的4个字节为方法名称

3.74 65 6c 6c

方法名称内容: 长度由2决度 ,内容为tell

4. 00 00 00 01

  方法顺序号,值1 =第一个(只有一个) 

以上对应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);
    }
  }

之后的字节描述参数:

5. 0c 00 01

   第一个字节代表 类型 0C=struct 

   后两个字节代表 序号 00 01 :第一个struct 

  

  public void writeFieldBegin(TField field) throws TException {
    writeByte(field.type);//1个字节的类型
    writeI16(field.id);//2个字节的顺序号
  }

 6. 08 00 01 

     第一个字节代表 类型 08= i32 整型

    后两个字节代表 序号 00 01 :struct 中第一个元素

   

  public void writeFieldBegin(TField field) throws TException {
    writeByte(field.type);//1个字节的元素类型
    writeI16(field.id);//2个字节的元素顺序号
  }
 7.00 00 03 ea

    上面指定了元素类型为 i32,即元素内容占用4个节,这是I32类型元素内容,值十进制==1002

    

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

8.0b 00 02

    第一个字节代表类型 0b=string 类型

    第二个字节代表顺序号 00 02 == struct 中第二个元素

   

  public void writeFieldBegin(TField field) throws TException {
    writeByte(field.type);
    writeI16(field.id);
  }

9.00 00 00 05 

   上面指定了第二个元素是string ,此处指定了string的长度是5,即之后的5个字节是第二个元素的内容

   

 10.75 73 65 72 31

  第二个元素的内容:user1

 9与10 代码:

   

  public void writeString(String str) throws TException {
    try {
      byte[] dat = str.getBytes("UTF-8");
      writeI32(dat.length);
      trans_.write(dat, 0, dat.length);
    } catch (UnsupportedEncodingException uex) {
      throw new TException("JVM DOES NOT SUPPORT UTF-8");
    }
  }

.......其它字节与上面类似,不再解释。

   

  

猜你喜欢

转载自java12345678.iteye.com/blog/2374900
今日推荐