C++项目中使用thrift对于optional中存在的坑

1、required字段没有__isset属性, 而默认的(就是既没有required,也没有optional)和optional的属性有该方法。
2、创建对象的时候,optional和默认的__isset属性为false,同样不设置该属性,而在经过thrift rpc传输之后,server端的默认的__isset属性为true。
3、有默认值的属性,不赋值的话,其值就是thrift中的默认值。
4、optional的如果没有设置__isset为true,则经过rpc传输(或者说是经过序列化再反序列化)之后,其值会丢失。

struct Student{
     
    1: required i32  sno,
    2: optional string  name,
    3: i64 age,
}
service Serv{
     
    void put(1: Student s),
}

一、

typedef struct _Student__isset {
     
  _Student__isset() : name(false), age(false) {
     }
  bool name :1;
  bool age :1;
} _Student__isset;

可有看到,该结构体重只包含了非required的属性。因此只有非required属性才有__isset的属性。

write

uint32_t Student::write(::apache::thrift::protocol::TProtocol* oprot) const {
     
  uint32_t xfer = 0;
  ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot);
  xfer += oprot->writeStructBegin("Student");

  xfer += oprot->writeFieldBegin("sno", ::apache::thrift::protocol::T_I32, 1);
  xfer += oprot->writeI32(this->sno);
  xfer += oprot->writeFieldEnd();

  if (this->__isset.name) {
     
    xfer += oprot->writeFieldBegin("name", ::apache::thrift::protocol::T_STRING, 2);
    xfer += oprot->writeString(this->name);
    xfer += oprot->writeFieldEnd();
  }
  xfer += oprot->writeFieldBegin("age", ::apache::thrift::protocol::T_I64, 3);
  xfer += oprot->writeI64(this->age);
  xfer += oprot->writeFieldEnd();

  xfer += oprot->writeFieldStop();
  xfer += oprot->writeStructEnd();
  return xfer;
}

对于optional的字段,其首先需要判断属性的__isset.是否为true,只有为true时才调用相应的write处理。 因此如果optional字段不设置其__isset,则序列化的时候会不处理

read

uint32_t Student::read(::apache::thrift::protocol::TProtocol* iprot) {
     

  ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot);
  uint32_t xfer = 0;
  std::string fname;
  ::apache::thrift::protocol::TType ftype;
  int16_t fid;

  xfer += iprot->readStructBegin(fname);

  using ::apache::thrift::protocol::TProtocolException;

  bool isset_sno = false;

  while (true)
  {
     
    xfer += iprot->readFieldBegin(fname, ftype, fid);
    if (ftype == ::apache::thrift::protocol::T_STOP) {
     
      break;
    }
    switch (fid)
    {
     
      case 1:
        if (ftype == ::apache::thrift::protocol::T_I32) {
     
          xfer += iprot->readI32(this->sno);
          isset_sno = true;
        } else {
     
          xfer += iprot->skip(ftype);
        }
        break;
      case 2:
        if (ftype == ::apache::thrift::protocol::T_STRING) {
     
          xfer += iprot->readString(this->name);
          this->__isset.name = true;
        } else {
     
          xfer += iprot->skip(ftype);
        }
        break;
      case 3:
        if (ftype == ::apache::thrift::protocol::T_I64) {
     
          xfer += iprot->readI64(this->age);
          this->__isset.age = true;
        } else {
     
          xfer += iprot->skip(ftype);
        }
        break;
      default:
        xfer += iprot->skip(ftype);
        break;
    }
    xfer += iprot->readFieldEnd();
  }

  xfer += iprot->readStructEnd();

  if (!isset_sno)
    throw TProtocolException(TProtocolException::INVALID_DATA);
  return xfer;
}

在read操作中对于非required字段,读取时将其isset设置为true。这也就是为什么server端isset的值是设置的。

if (!isset_sno)
    throw TProtocolException(TProtocolException::INVALID_DATA);

其对于required字段会进行check,如果没有,则抛出异常。
因此required字段还有此效果,即必须有该字段。

你可能感兴趣的:(thrift,http,protobuf协议)