Thrift的关键其实就是在定义好结构后,通过某种序列化方式进行网络传输交互,一般定义结构可以使用IDL的方式来描述各个字段属性等信息,这种方式可以支持跨语言的使用。对于纯Java的应用,也可以通过在类中添加注解的方式来实现,即把IDL中需要定义的信息,通过注解和注解中的信息来进行描述,同样可以达到定义结构的目的
定义好结构之后,就可以通过对应的TProtocol将数据结构进行发送和接收的序列化和反序列化即可,这次我们主要看下TProtocol中的一个实现–TBinaryProtocol
 
之前我们也看过thrift支持的一些结构类型,如struct、string、map、list等,具体可以看下对应枚举
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | public final class TType {public static final byte STOP   = 0;
 public static final byte VOID   = 1;
 public static final byte BOOL   = 2;
 public static final byte BYTE   = 3;
 public static final byte DOUBLE = 4;
 public static final byte I16    = 6;
 public static final byte I32    = 8;
 public static final byte I64    = 10;
 public static final byte STRING = 11;
 public static final byte STRUCT = 12;
 public static final byte MAP    = 13;
 public static final byte SET    = 14;
 public static final byte LIST   = 15;
 public static final byte ENUM   = 16;
 }
 
 | 
每次发送消息,都有一个消息类型的标识
| 12
 3
 4
 5
 6
 
 | 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;
 }
 
 | 
而TProtocol提供了对应这些结构的读写接口,我们可以大致看一下写接口,读接口也类似
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | writeMessageBegin(name, type, seq);
 writeMessageEnd();
 
 writeStructBegin(name);
 writeStructEnd();
 
 writeFieldBegin(name, type, id);
 writeFieldEnd();
 writeFieldStop();
 writeMapBegin(ktype, vtype, size);
 writeMapEnd();
 writeListBegin(etype, size);
 writeListEnd();
 writeSetBegin(etype, size);
 writeSetEnd();
 writeBool(bool);
 writeByte(byte);
 writeI16(i16);
 writeI32(i32);
 writeI64(i64);
 writeDouble(double);
 writeString(string);
 
 | 
通过阅读生成的代码,我们就可以看到具体的使用了,基本流程大致如下
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | 
 writeMessageBegin(name, type, seq);
 
 writeStructBegin(name);
 
 writeFieldBegin(name, type, id);
 
 writeString(string);
 
 writeFieldEnd();
 
 writeFieldBegin(name, type, id);
 
 writeString(string);
 
 writeFieldEnd();
 
 writeFieldStop();
 
 writeStructEnd();
 writeMessageEnd();
 
 | 
根据这些接口,掌握了写入流程后,我们可以不使用生成的代码来完成消息的接收和发送,下面我们只使用TBinaryProtocol来实现一个最简单的server服务(对应的接口参考第一篇文章),
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | // userService.thriftstruct User {
 1:string name;
 2:i32 age;
 }
 
 struct UserSearchResult {
 1:list<User> users;
 }
 
 service UserService {
 UserSearchResult searchUsers(1:string name);
 }
 
 | 
实现代码如下(只是为了展示功能)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 
 | TServerTransport serverTransport = new TServerSocket(12345);
 serverTransport.listen();
 final TTransport transport = serverTransport.accept();
 
 
 TProtocol protocol = new TBinaryProtocol(transport);
 
 while (true) {
 String name = "";
 
 final TMessage tMessage = protocol.readMessageBegin();
 if (tMessage.type == TMessageType.CALL) {
 
 protocol.readStructBegin();
 
 final TField tField = protocol.readFieldBegin();
 
 if (tField.id == 1) {
 
 name = protocol.readString();
 }
 
 protocol.readFieldEnd();
 protocol.readStructEnd();
 }
 protocol.readMessageEnd();
 
 System.out.println("Read param name:" + name);
 
 
 
 
 final TMessage respMessage = new TMessage("searchUsers", TMessageType.REPLY, tMessage.seqid);
 protocol.writeMessageBegin(respMessage);
 
 
 protocol.writeStructBegin(new TStruct("success"));
 
 protocol.writeFieldBegin(new TField("success", TType.STRUCT, (short) 0));
 
 
 protocol.writeStructBegin(new TStruct("searchResult"));
 
 final TField tField = new TField("users", TType.LIST, (short) 1);
 
 protocol.writeFieldBegin(tField);
 
 protocol.writeListBegin(new TList(TType.STRUCT,  2));
 
 protocol.writeStructBegin(new TStruct("user"));
 protocol.writeFieldBegin(new TField("name", TType.STRING, (short) 1));
 protocol.writeString("zhangsan1");
 protocol.writeFieldEnd();
 protocol.writeFieldBegin(new TField("age", TType.I32, (short) 2));
 protocol.writeI32(18);
 protocol.writeFieldEnd();
 protocol.writeFieldStop();
 protocol.writeStructEnd();
 
 protocol.writeStructBegin(new TStruct("user"));
 protocol.writeFieldBegin(new TField("name", TType.STRING, (short) 1));
 protocol.writeString("lisi1");
 protocol.writeFieldEnd();
 protocol.writeFieldBegin(new TField("age", TType.I32, (short) 2));
 protocol.writeI32(19);
 protocol.writeFieldEnd();
 protocol.writeFieldStop();
 protocol.writeStructEnd();
 
 protocol.writeListEnd();
 protocol.writeFieldEnd();
 protocol.writeFieldStop();
 protocol.writeStructEnd();
 
 protocol.writeFieldEnd();
 protocol.writeFieldStop();
 protocol.writeStructEnd();
 
 protocol.writeMessageEnd();
 
 protocol.getTransport().flush();
 }
 
 | 
之后启动服务,在使用之前的Client端方法进行调用
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | TTransport transport = new TSocket("localhost", 12345);
 transport.open();
 
 TProtocol protocol = new TBinaryProtocol(transport);
 UserService.Client client = new UserService.Client(protocol);
 
 UserSearchResult userRes = client.searchUsers("zhangsan");
 System.out.println(userRes);
 
 transport.close();
 
 | 
执行后可以发现可以实现之前的功能
| 12
 3
 4
 
 | // 服务端终端输出Read param name:zhangsan
 // 客户端终端输出
 UserSearchResult(users:[User(name:zhangsan1, age:18), User(name:lisi1, age:19)])
 
 | 
再进行深入的话,我们可以根据 TBinaryProtocol 中的具体发送信息逻辑,直接使用原生的Java Socket进行编程,只不过会更加麻烦一些,原理基本就是如此