分享

使用protobuf 作为网络消息协议

 quasiceo 2014-01-17

使用protobuf 作为网络消息协议

复制代码
#include <string>
#include <iostream>
#include <assert.h>
#include <stdint.h>

#include "person.pb.h"
#include "test.pb.h"

using namespace std;

class ProtoMsgHandle
{
public:

    /*  注册消息处理函数    */
    void    initHandles()
    {
        registerHandle(&ProtoMsgHandle::handleProtoPerson);
        registerHandle(&ProtoMsgHandle::handleProtoTest);
    }

    /*  处理网络消息  */
    void    handle(const char* data)
    {
        bool ret = false;
        const char* current = data;
        int32_t* p_packetlen = (int32_t*)current;   current += sizeof(*p_packetlen);
        int32_t* p_namelen = (int32_t*)current;     current += sizeof(*p_namelen);

        const char* p_name = current;
        string name(p_name, *p_namelen);            current += *p_namelen;

        do
        {
            msg_handle callback = m_callbacks[name];
            assert(callback != NULL);
            if(callback == NULL)
            {
                break;
            }

            const ::google::protobuf::Descriptor* descriptor = m_descriptors[name];
            assert(descriptor != NULL);
            if(descriptor == NULL)
            {
                break;
            }

            const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
            assert(prototype != NULL);
            if(prototype == NULL)
            {
                break;
            }

            google::protobuf::Message* msg = prototype->New();
            ret = msg->ParseFromArray(current, (*p_packetlen)-sizeof(*p_packetlen)-sizeof(*p_namelen)-*p_namelen);

            if(ret)
            {
                (this->*callback)(msg);
            }

        }while(0);
    }

private:
    void        handleProtoTest(test* test)
    {
        cout << test->price() << endl;
        cout << test->userid() << endl;
        cout << test->time() << endl;
    }

    void        handleProtoPerson(person* person)
    {
        cout << person->age() << endl;
        cout << person->userid() << endl;
        cout << person->name() << endl;
    }

private:
    typedef void (ProtoMsgHandle::*msg_handle)(::google::protobuf::Message*);

private:

    template<typename MSGTYPE>
    void        registerHandle(void (ProtoMsgHandle::*callback)(MSGTYPE*))
    {
        const ::google::protobuf::Descriptor* des = MSGTYPE::descriptor();
        assert(des != NULL);

        if(des != NULL)
        {
            m_callbacks[des->full_name()] = (msg_handle)callback;
            m_descriptors[des->full_name()] = des;
        }
    }

private:
    map<string, msg_handle>                                 m_callbacks;
    map<string, const ::google::protobuf::Descriptor*>      m_descriptors;
};

class ProtoMsgSender
{
public:
    /*  发送proto msg到指定缓冲区   */
    /*  int32_t -   packet_len
        int32_t     name_len
        char[]      name
        char[]      proto_data
    */
    template<typename MSGTYPE>
    void    sentProtoMsg(MSGTYPE& msg, char* buffer, int max_len)
    {
        char* current = buffer;
        int32_t* p_packetlen = (int32_t*)current;                       current += sizeof(*p_packetlen);
        int32_t* p_namelen = (int32_t*)current;                         current += sizeof(*p_namelen);

        string msg_name = MSGTYPE::descriptor()->full_name();
        *p_namelen = msg_name.size();
        strcpy(current, msg_name.c_str());                              current += msg_name.size();

        /*  判断是否成功  */
        msg.SerializeToArray(current, max_len - (current-buffer));      current += msg.GetCachedSize();

        *p_packetlen = (current-buffer);
    }
};

int main()
{
    ProtoMsgSender msgsender;
    ProtoMsgHandle msghandle;
    msghandle.initHandles();

    test t;
    t.set_price(100.0);
    t.set_userid(110);
    t.set_time(123);

    person person;
    person.set_age(18);
    person.set_userid(200508);
    person.set_name("irons");

    char tmp[10*1024];
    msgsender.sentProtoMsg(t, tmp, sizeof(tmp));
    msghandle.handle(tmp);

    msgsender.sentProtoMsg(person, tmp, sizeof(tmp));
    msghandle.handle(tmp);

    cin.get();

    return 0;
}

/*
message test
{
required int32 time = 1;
required int32 userid = 2;
required float price = 3;
optional string desc = 4;
}

message person
{
required int32 age = 1;
required int32 userid = 2;
optional string name = 3;
}
*/

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多