thrift 的required、optional探究
原因
经常使用thrift来编写rpc通信,但是对下面两个问题还是有些疑惑
- thrift 的required、optional和不写有什么区别
- optional不设置isset的话被传输后值?
实验
今天就自己编写代码测试了一下。如下:
定义book.thrift 如下:
1: namespace cpp codelab
2:
3: struct Book {
4: 1: i32 book_id
5: 2: string name
6: 3: optional string optional_attr,
7: 4: optional string optional_default_val_attr = "optional_default_val_attr",
8: 5: string default_attr,
9: 8: string default_val_attr = "default_val_attr",
10: 10: required string required_attr,
11: 11: required string required_default_val_attr = "equired_default_val_attr",
12: }
client代码如下:
1: int main(int argc, char **argv) {
2: boost::shared_ptr<TSocket> socket(new TSocket("localhost", 9090));
3: boost::shared_ptr<TTransport> transport(new TFramedTransport(socket));
4: boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
5:
6: HelloBookClient client(protocol);
7: transport->open();
8: Book book;
9: book.name = "hello thrift";
10: printf("book __isset.name: %d\n", book.__isset.name);
11: printf("book name: %s\n", book.name.c_str());
12: printf("book __isset.optional_attr: %d\n", book.__isset.optional_attr);
13: printf("book optional_attr: %s\n", book.optional_attr.c_str());
14: printf("book __isset.optional_default_val_attr: %d\n",
15: book.__isset.optional_default_val_attr);
16: printf("book optional_default_val_attr: %s\n",
17: book.optional_default_val_attr.c_str());
18: printf("book __isset.default_attr: %d\n", book.__isset.default_attr);
19: printf("book default_attr: %s\n", book.default_attr.c_str());
20: printf("book __isset.default_val_attr: %d\n",
21: book.__isset.default_val_attr);
22: printf("book default_val_attr: %s\n", book.default_val_attr.c_str());
23: // printf("book __isset.required_attr: %d\n",
24: // book.__isset.required_attr);
25: printf("book required_attr: %s\n", book.required_attr.c_str());
26: // printf("book __isset.required_default_val_attr: %d\n",
27: // book.__isset.required_default_val_attr);
28: printf("book required_default_val_attr: %s\n",
29: book.required_default_val_attr.c_str());
30:
31: client.ping(book);
32: transport->close();
33:
34: return 0;
35:
Server端代码:
1: class HelloBookHandler : virtual public HelloBookIf {
2: public:
3: HelloBookHandler() {
4: // Your initialization goes here
5: }
6:
7: void ping(const codelab::Book& book) {
8: // Your implementation goes here
9: printf("book __isset.name: %d\n", book.__isset.name);
10: printf("book name: %s\n", book.name.c_str());
11: printf("book __isset.optional_attr: %d\n", book.__isset.optional_attr);
12: printf("book optional_attr: %s\n", book.optional_attr.c_str());
13: printf("book __isset.optional_default_val_attr: %d\n",
14: book.__isset.optional_default_val_attr);
15: printf("book optional_default_val_attr: %s\n",
16: book.optional_default_val_attr.c_str());
17: printf("book __isset.default_attr: %d\n", book.__isset.default_attr);
18: printf("book default_attr: %s\n", book.default_attr.c_str());
19: printf("book __isset.default_val_attr: %d\n",
20: book.__isset.default_val_attr);
21: printf("book default_val_attr: %s\n", book.default_val_attr.c_str());
22: // printf("book __isset.required_attr: %d\n",
23: // book.__isset.required_attr);
24:
25: printf("book required_attr: %s\n", book.required_attr.c_str());
26: // printf("book __isset.required_default_val_attr: %d\n",
27: // book.__isset.required_default_val_attr);
28: printf("book required_default_val_attr: %s\n",
29: book.required_default_val_attr.c_str());
30: }
31: };
32:
33: int main(int argc, char **argv) {
34: int port = 9090;
35: boost::shared_ptr<HelloBookHandler> handler(new HelloBookHandler());
36: boost::shared_ptr<TProcessor> processor(new HelloBookProcessor(handler));
37: boost::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
38: boost::shared_ptr<TTransportFactory> transportFactory(
39: new TFramedTransportFactory());
40: boost::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
41:
42: TSimpleServer server(processor, serverTransport,
43: transportFactory, protocolFactory);
44: server.serve();
45: return 0;
46: }
Client端执行结果:
Server端执行结果:
而对client代码修改如下,
server端的执行结果分别如下:
即没有设置isset为true的时候optional_attr的值到server被丢失了。而设置为true之后才能在server获取到
经过上面的测试,得到以下结论:
- required字段没有__isset属性, 而默认的(就是既没有required,也没有optional)和optional的属性有该方法。
- 创建对象的时候,optional和默认的__isset属性为false,同样不设置该属性,而在经过thrift rpc传输之后,server端的默认的__isset属性为true,而optional的__isset的属性为true。
- 有默认值的属性,不赋值的话,其值就是thrift中的默认值。
- optional的如果没有设置__isset为true,则经过rpc传输(或者说是经过序列化再反序列化)之后,其值会丢失。
为什么会有上面的结果呢:
原因分析
查看thrift生成的文件:
其中book_types.h 如下:
1: /**
2: * Autogenerated by Thrift
3: *
4: * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5: */
6: #ifndef book_TYPES_H
7: #define book_TYPES_H
8:
9: #include <Thrift.h>
10: #include <TApplicationException.h>
11: #include <protocol/TProtocol.h>
12: #include <transport/TTransport.h>
13:
14:
15:
16: namespace codelab {
17:
18: typedef struct _Book__isset {
19: _Book__isset() : book_id(false), name(false), optional_attr(false), optional_default_val_attr(false), default_attr(false), default_val_attr(false) {}
20: bool book_id;
21: bool name;
22: bool optional_attr;
23: bool optional_default_val_attr;
24: bool default_attr;
25: bool default_val_attr;
26: } _Book__isset;
27:
28: class Book {
29: public:
30:
31: static const char* ascii_fingerprint; // = "EC22AAB82386E1FAA959FB075574467D";
32: static const uint8_t binary_fingerprint[16]; // = {0xEC,0x22,0xAA,0xB8,0x23,0x86,0xE1,0xFA,0xA9,0x59,0xFB,0x07,0x55,0x74,0x46,0x7D};
33:
34: Book() : book_id(0), name(""), optional_attr(""), optional_default_val_attr("optional_default_val_attr"), default_attr(""), default_val_attr("default_val_attr"), required_attr(""), required_default_val_attr("equired_default_val_attr") {
35: }
36:
37: virtual ~Book() throw() {}
38:
39: int32_t book_id;
40: std::string name;
41: std::string optional_attr;
42: std::string optional_default_val_attr;
43: std::string default_attr;
44: std::string default_val_attr;
45: std::string required_attr;
46: std::string required_default_val_attr;
47:
48: _Book__isset __isset;
49:
50: bool operator == (const Book & rhs) const
51: {
52: if (!(book_id == rhs.book_id))
53: return false;
54: if (!(name == rhs.name))
55: return false;
56: if (__isset.optional_attr != rhs.__isset.optional_attr)
57: return false;
58: else if (__isset.optional_attr && !(optional_attr == rhs.optional_attr))
59: return false;
60: if (__isset.optional_default_val_attr != rhs.__isset.optional_default_val_attr)
61: return false;
62: else if (__isset.optional_default_val_attr && !(optional_default_val_attr == rhs.optional_default_val_attr))
63: return false;
64: if (!(default_attr == rhs.default_attr))
65: return false;
66: if (!(default_val_attr == rhs.default_val_attr))
67: return false;
68: if (!(required_attr == rhs.required_attr))
69: return false;
70: if (!(required_default_val_attr == rhs.required_default_val_attr))
71: return false;
72: return true;
73: }
74: bool operator != (const Book &rhs) const {
75: return !(*this == rhs);
76: }
77:
78: bool operator < (const Book & ) const;
79:
80: uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
81: uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;
82:
83: };
84:
85: } // namespace
86:
87: #endif
book_types.cpp 文件如下:
1: /**
2: * Autogenerated by Thrift
3: *
4: * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5: */
6: #include "codelab/thrift/proto/gen-cpp/book_types.h"
7:
8: namespace codelab {
9:
10: const char* Book::ascii_fingerprint = "EC22AAB82386E1FAA959FB075574467D";
11: const uint8_t Book::binary_fingerprint[16] = {0xEC,0x22,0xAA,0xB8,0x23,0x86,0xE1,0xFA,0xA9,0x59,0xFB,0x07,0x55,0x74,0x46,0x7D};
12:
13: uint32_t Book::read(::apache::thrift::protocol::TProtocol* iprot) {
14:
15: uint32_t xfer = 0;
16: std::string fname;
17: ::apache::thrift::protocol::TType ftype;
18: int16_t fid;
19:
20: xfer += iprot->readStructBegin(fname);
21:
22: using ::apache::thrift::protocol::TProtocolException;
23:
24: bool isset_required_attr = false;
25: bool isset_required_default_val_attr = false;
26:
27: while (true)
28: {
29: xfer += iprot->readFieldBegin(fname, ftype, fid);
30: if (ftype == ::apache::thrift::protocol::T_STOP) {
31: break;
32: }
33: switch (fid)
34: {
35: case 1:
36: if (ftype == ::apache::thrift::protocol::T_I32) {
37: xfer += iprot->readI32(this->book_id);
38: this->__isset.book_id = true;
39: } else {
40: xfer += iprot->skip(ftype);
41: }
42: break;
43: case 2:
44: if (ftype == ::apache::thrift::protocol::T_STRING) {
45: xfer += iprot->readString(this->name);
46: this->__isset.name = true;
47: } else {
48: xfer += iprot->skip(ftype);
49: }
50: break;
51: case 3:
52: if (ftype == ::apache::thrift::protocol::T_STRING) {
53: xfer += iprot->readString(this->optional_attr);
54: this->__isset.optional_attr = true;
55: } else {
56: xfer += iprot->skip(ftype);
57: }
58: break;
59: case 4:
60: if (ftype == ::apache::thrift::protocol::T_STRING) {
61: xfer += iprot->readString(this->optional_default_val_attr);
62: this->__isset.optional_default_val_attr = true;
63: } else {
64: xfer += iprot->skip(ftype);
65: }
66: break;
67: case 5:
68: if (ftype == ::apache::thrift::protocol::T_STRING) {
69: xfer += iprot->readString(this->default_attr);
70: this->__isset.default_attr = true;
71: } else {
72: xfer += iprot->skip(ftype);
73: }
74: break;
75: case 8:
76: if (ftype == ::apache::thrift::protocol::T_STRING) {
77: xfer += iprot->readString(this->default_val_attr);
78: this->__isset.default_val_attr = true;
79: } else {
80: xfer += iprot->skip(ftype);
81: }
82: break;
83: case 10:
84: if (ftype == ::apache::thrift::protocol::T_STRING) {
85: xfer += iprot->readString(this->required_attr);
86: isset_required_attr = true;
87: } else {
88: xfer += iprot->skip(ftype);
89: }
90: break;
91: case 11:
92: if (ftype == ::apache::thrift::protocol::T_STRING) {
93: xfer += iprot->readString(this->required_default_val_attr);
94: isset_required_default_val_attr = true;
95: } else {
96: xfer += iprot->skip(ftype);
97: }
98: break;
99: default:
100: xfer += iprot->skip(ftype);
101: break;
102: }
103: xfer += iprot->readFieldEnd();
104: }
105:
106: xfer += iprot->readStructEnd();
107:
108: if (!isset_required_attr)
109: throw TProtocolException(TProtocolException::INVALID_DATA);
110: if (!isset_required_default_val_attr)
111: throw TProtocolException(TProtocolException::INVALID_DATA);
112: return xfer;
113: }
114:
115: uint32_t Book::write(::apache::thrift::protocol::TProtocol* oprot) const {
116: uint32_t xfer = 0;
117: xfer += oprot->writeStructBegin("Book");
118: xfer += oprot->writeFieldBegin("book_id", ::apache::thrift::protocol::T_I32, 1);
119: xfer += oprot->writeI32(this->book_id);
120: xfer += oprot->writeFieldEnd();
121: xfer += oprot->writeFieldBegin("name", ::apache::thrift::protocol::T_STRING, 2);
122: xfer += oprot->writeString(this->name);
123: xfer += oprot->writeFieldEnd();
124: if (this->__isset.optional_attr) {
125: xfer += oprot->writeFieldBegin("optional_attr", ::apache::thrift::protocol::T_STRING, 3);
126: xfer += oprot->writeString(this->optional_attr);
127: xfer += oprot->writeFieldEnd();
128: }
129: if (this->__isset.optional_default_val_attr) {
130: xfer += oprot->writeFieldBegin("optional_default_val_attr", ::apache::thrift::protocol::T_STRING, 4);
131: xfer += oprot->writeString(this->optional_default_val_attr);
132: xfer += oprot->writeFieldEnd();
133: }
134: xfer += oprot->writeFieldBegin("default_attr", ::apache::thrift::protocol::T_STRING, 5);
135: xfer += oprot->writeString(this->default_attr);
136: xfer += oprot->writeFieldEnd();
137: xfer += oprot->writeFieldBegin("default_val_attr", ::apache::thrift::protocol::T_STRING, 8);
138: xfer += oprot->writeString(this->default_val_attr);
139: xfer += oprot->writeFieldEnd();
140: xfer += oprot->writeFieldBegin("required_attr", ::apache::thrift::protocol::T_STRING, 10);
141: xfer += oprot->writeString(this->required_attr);
142: xfer += oprot->writeFieldEnd();
143: xfer += oprot->writeFieldBegin("required_default_val_attr", ::apache::thrift::protocol::T_STRING, 11);
144: xfer += oprot->writeString(this->required_default_val_attr);
145: xfer += oprot->writeFieldEnd();
146: xfer += oprot->writeFieldStop();
147: xfer += oprot->writeStructEnd();
148: return xfer;
149: }
150:
151: } // namespace
thrift 的required、optional探究的更多相关文章
- Thrift中required和optional
最近在搞Thrift,对其字段声明中的required关键字有所误解,仔细调试了一下才明白其真实含义. required的意思不是说声明对象时,必须填这个值,而是Thrift在传输(序列化)过程中无论 ...
- How to fix the bug “Expected "required", "optional", or "repeated".”?
参考:https://github.com/tensorflow/models/issues/1834 You need to download protoc version 3.3 (already ...
- Thrift.0
0. Thrift的特性 1. 安装Thrift编译器 [Todo] http://thrift.apache.org/docs/install/ http://thrift.apache.org/d ...
- Netty学习——Thrift的入门使用
Netty学习——Thrift的入门使用 希望你能够,了解并使用它.因为它是一个效率很高的框架 官网地址:http://thrift.apache.org/ 1.Thrift数据类型 一门技术如果需要 ...
- Google 开源技术protobuf
http://blog.csdn.net/hguisu/article/details/20721109#0-tsina-1-1601-397232819ff9a47a7b7e80a40613cfe1 ...
- Potocol Buffer详解
protocol安装及使用 上一篇博文介绍了一个综合案例,这篇将详细介绍protocol buffer. 为什么使用protocol buffer? java默认序列化效率较低. apache的thr ...
- gRPC学习
概述 gRPC 一开始由 google 开发,是一款语言中立.平台中立.开源的远程过程调用(RPC)系统. 在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法, ...
- Storm Flow
A Stream represents the core data model in Trident, and can be thought of as a "stream" of ...
- iOS:以前笔记,未整理版。太多了,先放着吧。。。。。。。
1. -(void)timetick { _d = 0; NSTimer *newtime =[NSTimer scheduledTimerWithTimeInterval:1 target:self ...
随机推荐
- 十五、API请求接口-远程服务器返回错误: (400) 错误的请求错误
一.远程服务器返回错误: (400) 错误的请求错误 捕获异常查看具体错误 using Newtonsoft.Json; using System; using System.Collections. ...
- STM点滴一
就就是你用BSRR和BRR去改变管脚状态的时候,没有被中断打断的风险.也就不需要关闭中断. This way, there is no risk that an IRQ occurs between ...
- JavaSE---IO体系
1.BIO 1.1 Block IO,同步阻塞IO: 1.2 eg:java.io 包下的 InputStream . OutputStream. Writer.Reader... j ...
- CSS 布局 - Overflow
CSS 布局 - Overflow CSS overflow 属性用于控制内容溢出元素框时显示的方式. 这里的文本内容是可以滚动的,滚动条方向是垂直方向.dd马达价格 这里的文本内容是可以滚动的,滚动 ...
- PHP filter_has_var() 函数
「大理石平台」大理石平台上的裂缝是怎么回事? 定义和用法 filter_has_var() 函数检查是否存在指定输入类型的变量. 如果成功则返回 TRUE,如果失败则返回 FALSE. 语法 filt ...
- 初学Linux基本的命令操作应当记牢
Linux管理文件和目录的命令 命令 功能 命令 功能 pwd 显示当前目录 ls 查看目录下的内容 cd 改变所在目录 cat 显示文件的内容 grep 在文件中查找某字符 cp 复制文件 touc ...
- 从输入 URL 到页面展示,到底发生了什么
从输入 URL 到页面展示,到底发生了什么 1.输入URL 当我们开始在浏览器中输入网址的时候,浏览器其实就已经在智能的匹配可能得 url 了,他会从历史记录,书签等地方,找到已经输入的字符串可能对应 ...
- undefined null测试
测试浏览器:chrome 当有父元素的子元素未定义时undefined和null均为true,类型为undefined 当元素赋给null后undefined和null均为true,类型为object ...
- js全局变量优点和缺点
全局变量的优点:可以减少变量的个数,减少由于实际参数和形式参数的数据传递带来的时间消耗. 全局变量的缺点: (1)全局变量保存在静态存贮区,程序开始运行时为其分配内存,程序结束释放该内存.与局部变量的 ...
- 接口调用post请求参数在body中
package com.ynhrm.common.utils; import com.alibaba.fastjson.JSONObject; import lombok.Data; import o ...