信息传递工具protobuf通过pb的反射来赋值

作者:袖梨 2022-06-25

最近因为项目逻辑方面都做的差不多了,于是赶紧去做做测试工作,免得项目上线之后出问题,于是打算用配置的形式做一个类似与白盒测试工具的东西出来。

因为项目使用pb来做协议通讯,所以配置的xml也是类似于pb,将pb的字段和类型配置进去,然后加上值,一个协议结构就可以了,现在只能通过修改值来做测试,后面会改动的更智能化一些,例如某个行为的次数,某个行为更随机等等。

去读了一下陈硕的关于pb处理协议的反射,学到了不少东西,同时对pb的一些东西理解更深刻了,google还是大牛很多。

1.如何处理pb的反射,通过协议字串动态生成一个协议

pb提供了一个强大的DescriptorPool::generated_pool()

代码如下:

 代码如下 复制代码
inline google::protobuf::Message* CreateMessage(const std::string& msg)
{
    google::protobuf::Message* message = NULL;
    const google::protobuf::Descriptor* descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("ProtoMsg." + msg);
    if (descriptor)
    {
        const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
        if (prototype)
        {
            message = prototype->New();
        }
    }

    return message;
}

inline void ReleaseMessage(google::protobuf::Message* pMsg)
{
    if (NULL != pMsg)
    {
        pMsg->Clear();
        delete pMsg;
    }
}



这两个函数可以动态生成pb的message,其中ProtoMsg是你pb package的名字

2.通过反射将配置中的值设置进pb字段

pb的Message基类提供了一个Reflection,这个类非常强大

代码如下

 代码如下 复制代码
// mstrCurMsg 当前正在执行的协议
google::protobuf::Message* pMsg = Test::CreateMessage(mstrCurMsg);
const google::protobuf::Descriptor* pDescriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("ProtoMsg." + mstrCurMsg);
assert(NULL != pDescriptor);

// 这一个可以获取到反射类,然后可以将配置中值赋值进去
const google::protobuf::Reflection* pReflection = pMsg->GetReflection();
assert(NULL != pReflection);

for (int i = 0; i < pDescriptor->field_count(); ++i)
{
    const google::protobuf::FieldDescriptor* pFieldDescriptor = pDescriptor->field(i);
    assert(NULL != pFieldDescriptor);

    const std::string& strFieldName = pFieldDescriptor->name();
   
    const TestConfigModule::MsgEntry* pMsgEntry = pMsgStruct->GetMsgEntry(strFieldName);
    assert(NULL != pMsgEntry);

    // 读取字段类型,顺带可以做类型检查
    assert(pMsgEntry->mnType == pFieldDescriptor->type());

    // 设置值
    switch (pMsgEntry->mnType)
    {
    case Test::TYPE_STRING:
        pReflection->SetString(pMsg, pFieldDescriptor, pMsgEntry->mstrValue);
        break;
    // ...
    default:
        break;
    }
}

std::string strData;
if (!pMsg->SerializeToString(&strData))
{
    m_pLogModule->LogNormal("Test stop, cannot SerializeToString ", mstrCurMsg, __FUNCTION__, __LINE__);
    return;
}

Test::ReleaseMessage(pMsg);



通过这样的步骤,就可以自动创建message和对field赋值了

相关文章

精彩推荐