方法1:
message person
{
required int32 age = 1;
required int32 userid = 2;
optional string name = 3;
}
message test
{
required int32 time = 1;
required int32 userid = 2;
required float price = 3;
optional string desc = 4;
}
1 #include <string> 2 #include <iostream> 3 #include <assert.h> 4 #include <stdint.h> 5 6 #include "person.pb.h" 7 #include "test.pb.h" 8 9 using namespace std; 10 11 class ProtoMsgHandle 12 { 13 public: 14 /* 注册消息处理函数 */ 15 void initHandles() 16 { 17 registerHandle(&ProtoMsgHandle::handleProtoPerson); 18 registerHandle(&ProtoMsgHandle::handleProtoTest); 19 } 20 21 /* 处理网络消息 22 * data 为一个完整的数据包 23 */ 24 void handle(const char* data) 25 { 26 bool ret = false; 27 28 const char * current=data; 29 30 //在网络上传输的一个数据包总长度 31 int packetLength=0; 32 33 //从第一个位置上获取到数据包总长度 34 memcpy(&packetLength, data, sizeof(int32_t)); 35 36 //指针后移 37 current+=sizeof(int32_t); 38 39 //Message名字的长度 40 int protoNameLength=0; 41 42 //从第二个位置上获取Message的名字的长度 43 memcpy(&protoNameLength, current, sizeof(int32_t)); 44 45 //指针后移 46 current+=sizeof(int32_t); 47 48 //从第三个位置上获取Message的名字 49 string name(current,protoNameLength); 50 51 //指针后移 52 current+=protoNameLength; 53 54 //取得Message的字节数 55 int messageSize=packetLength-(sizeof(int32_t)+sizeof(int32_t)+protoNameLength); 56 57 do{ 58 59 msg_handle callback = m_callbacks[name]; 60 61 assert(callback != NULL); 62 63 if(callback == NULL) 64 { 65 std::cout<<"proto "<<name<<" had not register handler"<<std::endl; 66 break; 67 } 68 const ::google::protobuf::Descriptor* descriptor = m_descriptors[name]; 69 assert(descriptor != NULL); 70 if(descriptor == NULL) 71 { 72 std::cout<<"proto "<<name<<" had no descriptor"<<std::endl; 73 break; 74 } 75 const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor); 76 assert(prototype != NULL); 77 if(prototype == NULL) 78 { 79 std::cout<<"proto "<<name<<" had no prototype"<<std::endl; 80 break; 81 } 82 google::protobuf::Message* msg = prototype->New(); 83 ret = msg->ParseFromArray(current,messageSize); 84 if(ret) 85 { 86 (this->*callback)(msg); 87 } 88 else 89 { 90 std::cout<<"proto "<<name<<" parse fail"<<std::endl; 91 } 92 93 }while(0); 94 } 95 private: 96 void handleProtoTest(test* test) 97 { 98 cout <<"test->price()="<< test->price() << endl; 99 cout << "test->userid()="<<test->userid() << endl; 100 cout << "test->time()="<<test->time() << endl; 101 } 102 void handleProtoPerson(person* person) 103 { 104 cout << "person->age()="<<person->age() << endl; 105 cout << "person->userid()="<<person->userid() << endl; 106 cout << "person->name()="<<person->name() << endl; 107 } 108 109 private: 110 111 typedef void (ProtoMsgHandle::*msg_handle)(::google::protobuf::Message*); 112 113 map<string, msg_handle> m_callbacks; 114 115 map<string, const ::google::protobuf::Descriptor*> m_descriptors; 116 117 template<typename MSGTYPE> void registerHandle(void (ProtoMsgHandle::*callback)(MSGTYPE*)) 118 { 119 const ::google::protobuf::Descriptor*des =MSGTYPE::descriptor(); 120 assert(des != NULL); 121 if(des != NULL) 122 { 123 m_callbacks[des->full_name()] = (msg_handle)callback; 124 m_descriptors[des->full_name()] = des; 125 } 126 } 127 128 129 }; 130 131 class ProtoMessageSender 132 { 133 public: 134 /* 发送proto msg到指定缓冲区 135 * int32_t packetLength 数据包总长度 136 * int32_t messageNameLength 消息名长度 137 * char[] messageName 消息名 138 * char[] Message 消息 139 * char* buffer 缓冲区 140 * int maxLength 消息的最大长度 141 */ 142 template<typename MSGTYPE> static int sendMessageToBuffer(MSGTYPE& msg, char* buffer, int maxLength){ 143 144 char * current=buffer; 145 146 //Message的字节数 147 int messageSize=msg.ByteSize(); 148 149 //Message的名字 150 string messageName=MSGTYPE::descriptor()->full_name(); 151 152 //Message名字的长度 153 size_t messageNameLength=messageName.size(); 154 155 //消息组成 messageSize+messageNameLength+messageName+Message 156 size_t packetLength=sizeof(int32_t)+sizeof(int32_t)+messageNameLength+messageSize; 157 158 if (packetLength>maxLength) { 159 return -1; 160 } 161 162 //将数据包总长度放在第一个位置 163 memcpy(current, &packetLength, sizeof(int32_t)); 164 165 //指针后移 166 current+=sizeof(int32_t); 167 168 //将Message名称长度放在第二个位置 169 memcpy(current, &messageNameLength, sizeof(int32_t)); 170 171 //指针后移 172 current+=sizeof(int32_t); 173 174 //将协议名称放在第三个位置上 175 strcpy(current,messageName.c_str()); 176 177 //指针后移 178 current+=messageNameLength; 179 180 //将Message放在第四个位置上 181 msg.SerializeToArray(current,messageSize); 182 183 return (int)packetLength; 184 185 } 186 }; 187 188 int main() 189 { 190 191 ProtoMsgHandle msghandle; 192 msghandle.initHandles(); 193 194 test t; 195 t.set_price(100.0); 196 t.set_userid(110); 197 t.set_time(123); 198 199 person person; 200 person.set_age(18); 201 person.set_userid(200508); 202 person.set_name("irons"); 203 204 char tmp[10*1024]; 205 ProtoMessageSender::sendMessageToBuffer(t, tmp, sizeof(tmp)); 206 msghandle.handle(tmp); 207 208 ProtoMessageSender::sendMessageToBuffer(person, tmp, sizeof(tmp)); 209 msghandle.handle(tmp); 210 211 cin.get(); 212 return 0; 213 }
方法2:
http://my.oschina.net/cxh3905/blog/159122
比较:
方法1把每种消息注册到链表中,当有消息来时,迭代处理,每个消息对应一个回调函数。
方法2只有1种消息,里面有个成员msg type,根据这个type做相应的处理。
前者更直观,结构清晰,每个消息占用空间合理,但效率地下。
后者效率更高,但所有数据混杂在一起,代码阅读性差。