Apache Thrift:在列表前使用“可选”时,C ++服务器似乎未正确返回它

YU Chang

你好!每个人,我都有与此类似的问题:

关于节俭功能返回列表

当列表具有“可选”修饰符时,节俭的C ++服务器将始终将其返回为null / undef。

另外,如果一个可选列表包含的结构,则该结构的任何字段都不能设置为“可选”,否则将返回null / undef值。

删除所有“可选”修饰符后,一切正常。

有人可以告诉我为什么我不能在列表前使用“可选”吗?


这是旧文件:

namespace cpp thrifttest
namespace perl thrifttest

struct Pair {
    1: optional string a, 
    2: optional string b
}

struct Result {
    1: optional list<string> strList,
    2: optional list<Pair> pairList
}

service Test {

    Result listTest()

}

这是C ++代码(服务器):

#include "gen-cpp/Test.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>

#include <iostream>

using namespace std;

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using boost::shared_ptr;

using namespace  ::thrifttest;

class TestHandler : virtual public TestIf {
    public:
        TestHandler() {
            // Your initialization goes here
        }

        void listTest(Result& _return) {

            _return.strList.push_back("Test");
            _return.strList.push_back("one level list");
            cout << "strList size: " << _return.strList.size() << endl;

            Pair pair;
            pair.a = "Test";
            pair.b = "two level list";
            _return.pairList.push_back(pair);
            cout << "pairList size: " << _return.pairList.size() << endl;

            printf("call listTest\n");
        }

};

int main(int argc, char **argv) {
    int port = 9595;
    shared_ptr<TestHandler> handler(new TestHandler());
    shared_ptr<TProcessor> processor(new TestProcessor(handler));
    shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
    shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
    shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

    TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
    server.serve();
    return 0;
}

这是perl代码(客户端):

#!/usr/bin/perl

use v5.12;
use warnings;
use autodie;

use utf8;
use Data::Dumper;

use lib 'gen-perl';

use thrifttest::Test;
use thrifttest::Constants;
use thrifttest::Types;

use Thrift;
use Thrift::BinaryProtocol;
use Thrift::Socket;
use Thrift::BufferedTransport;


my $socket    = new Thrift::Socket('localhost', 9595);
my $transport = new Thrift::BufferedTransport($socket, 1024, 1024);
my $protocol  = new Thrift::BinaryProtocol($transport);
my $client    = new thrifttest::TestClient($protocol);


eval {
    $transport->open();
    my $result = $client->listTest;
    say Dumper($result);
    $transport->close();
};
say $@ if $@;

C ++服务器输出:

strList size: 2
pairList size: 1
call listTest

perl客户端输出:

$VAR1 = bless( {
                 'pairList' => undef,
                 'strList' => undef
               }, 'thrifttest::Result' );

PS:我的开发环境是CentOS 7,GCC 4.8.3,Perl 5.16,旧版0.9.3

詹斯

我错了,这不是一个真正的错误,它只是一些不幸的设计,并不是真正的傻瓜,而是允许用户制作Dumb Things™。问题在于optional运算符的语义以及如何在C ++中实现它。

假设我们有这个IDL:

struct Xtruct2
{
  1: i8     byte_thing,  
  2: Xtruct struct_thing,
  3: i32    i32_thing
}

生成的代码(尤其是write()方法)如下所示:

uint32_t Xtruct2::write(::apache::thrift::protocol::TProtocol* oprot) const {
  //...
  xfer += oprot->writeFieldBegin("struct_thing", ::apache::thrift::protocol::T_STRUCT, 2);
  xfer += this->struct_thing.write(oprot);
  xfer += oprot->writeFieldEnd();
  //...
}

如果现在修改IDL并添加说明optional符:

struct Xtruct2
{
  1: i8     byte_thing,  
  2: optional Xtruct struct_thing,
  3: i32    i32_thing
}

生成的代码看起来略有不同:

uint32_t Xtruct2::write(::apache::thrift::protocol::TProtocol* oprot) const {
  //...
  if (this->__isset.struct_thing) {
    xfer += oprot->writeFieldBegin("struct_thing", ::apache::thrift::protocol::T_STRUCT, 2);
    xfer += this->struct_thing.write(oprot);
    xfer += oprot->writeFieldEnd();
  }
  //...
}

节俭有三种requiredness的:requiredoptional和默认。如果requiredoptional指定或未指定,则隐式假定使用后者(这就是为什么默认需求没有特殊关键字的原因)。相对于读写这些字段的语义如下:

    requiredness        write field?        read field?         
    ----------------------------------------------------------------------
    required            always              always, must be present
    (default)           always              if present, may be missing
    optional            only if set         if present, may be missing

因此optional,与默认值相比,更改的是写方法的行为。虽然始终写入默认字段,但optional仅有条件地写入字段可以通过__isset标志来检查该标志,该标志由一个位集组成,每个字段的位数不为1 required如果设置了其中的相应位标志__isset,则可以使用字段值。如果位标志不存在,则字段值尚未初始化,因此不应使用。

到目前为止,这并不是什么大问题。但是有一个陷阱optional可以解决:默认值和字段可以在C ++中访问和使用,即使未设置位标志(因为它们就在那里)也是如此。在默认情况下,这没什么大不了的:您分配您的值,并且由于始终写入字段,因此基本上不会发生任何不良情况。反序列化字段时,将设置该字段的位标志(请参见生成的代码)。

但是,当您选择加入时,情况发生了变化optional:现在突然之间,有责任通过__isset直接访问或通过生成的setter方法(在我们的情况下为:)正确设置标志

void Xtruct2::__set_struct_thing(const Xtruct& val) {
  this->struct_thing = val;
__isset.struct_thing = true;
}

我的假设是,应该不可能访问尚未设置的可选字段,但事实证明,这似乎是设计使然。我仍然认为设计在这里容易出错。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Apache Thrift:在列表前使用“可选”时,C ++服务器似乎未正确返回它

来自分类Dev

无法在Ubuntu服务器上与apache2一起使用SSL,端口443似乎未打开

来自分类Dev

使用Apache Thrift的服务复用

来自分类Dev

如何使用PHP和Apache Web服务器正确调用Python Pyro客户端?

来自分类Dev

非阻塞服务器Apache Thrift Python

来自分类Dev

运行Apache Thrift服务器的内存泄漏

来自分类Dev

Apache Thrift 仅用于处理,而非服务器

来自分类Dev

请求端口22时,Apache 2转发代理服务器返回403

来自分类Dev

部署在apache tomcat 7.0服务器上时,读取目录返回null

来自分类Dev

使用Apache FTPClient使FTP服务器返回时间戳列出的文件

来自分类Dev

使用Apache Thrift使用HTTP协议实现服务器/客户端

来自分类Dev

使用Apache Thrift的服务多路复用

来自分类Dev

如何获得Apache Thrift为多线程服务器生成c ++代码?

来自分类Dev

为什么apache2服务器不工作,当我检查状态时,它显示以下内容!:(

来自分类Dev

Centos Apache服务器似乎没有重定向

来自分类Dev

使用2个客户端时,Apache Thrift教程客户端卡住了-如何使服务器执行多任务处理?

来自分类Dev

启动Apache Tomcat服务器时出错

来自分类Dev

启动apache服务器时遇到问题

来自分类Dev

403在配置apache / httpd服务器时禁止

来自分类Dev

具有Apache服务器的C#网站

来自分类Dev

如何使用Docker容器作为Apache服务器?

来自分类Dev

使用python设置Apache服务器范围的变量

来自分类Dev

使用.htaccess修改URL [Apache Ubuntu服务器]

来自分类Dev

使用Apache服务器设置VSFTPD权限

来自分类Dev

使用Apache作为代理服务器+ Tomcat

来自分类Dev

如何在Apache Web服务器上使用geminabox

来自分类Dev

在单个服务器上使用Apache HBase

来自分类Dev

使用PHP的Apache服务器和MOD_PLSQL

来自分类Dev

使用Apache Vhost路由服务器请求?

Related 相关文章

  1. 1

    Apache Thrift:在列表前使用“可选”时,C ++服务器似乎未正确返回它

  2. 2

    无法在Ubuntu服务器上与apache2一起使用SSL,端口443似乎未打开

  3. 3

    使用Apache Thrift的服务复用

  4. 4

    如何使用PHP和Apache Web服务器正确调用Python Pyro客户端?

  5. 5

    非阻塞服务器Apache Thrift Python

  6. 6

    运行Apache Thrift服务器的内存泄漏

  7. 7

    Apache Thrift 仅用于处理,而非服务器

  8. 8

    请求端口22时,Apache 2转发代理服务器返回403

  9. 9

    部署在apache tomcat 7.0服务器上时,读取目录返回null

  10. 10

    使用Apache FTPClient使FTP服务器返回时间戳列出的文件

  11. 11

    使用Apache Thrift使用HTTP协议实现服务器/客户端

  12. 12

    使用Apache Thrift的服务多路复用

  13. 13

    如何获得Apache Thrift为多线程服务器生成c ++代码?

  14. 14

    为什么apache2服务器不工作,当我检查状态时,它显示以下内容!:(

  15. 15

    Centos Apache服务器似乎没有重定向

  16. 16

    使用2个客户端时,Apache Thrift教程客户端卡住了-如何使服务器执行多任务处理?

  17. 17

    启动Apache Tomcat服务器时出错

  18. 18

    启动apache服务器时遇到问题

  19. 19

    403在配置apache / httpd服务器时禁止

  20. 20

    具有Apache服务器的C#网站

  21. 21

    如何使用Docker容器作为Apache服务器?

  22. 22

    使用python设置Apache服务器范围的变量

  23. 23

    使用.htaccess修改URL [Apache Ubuntu服务器]

  24. 24

    使用Apache服务器设置VSFTPD权限

  25. 25

    使用Apache作为代理服务器+ Tomcat

  26. 26

    如何在Apache Web服务器上使用geminabox

  27. 27

    在单个服务器上使用Apache HBase

  28. 28

    使用PHP的Apache服务器和MOD_PLSQL

  29. 29

    使用Apache Vhost路由服务器请求?

热门标签

归档