方法1:ios
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:ui
http://my.oschina.net/cxh3905/blog/159122this
比較:google
方法1把每種消息註冊到鏈表中,當有消息來時,迭代處理,每一個消息對應一個回調函數。spa
方法2只有1種消息,裏面有個成員msg type,根據這個type作相應的處理。.net
前者更直觀,結構清晰,每一個消息佔用空間合理,但效率地下。prototype
後者效率更高,但全部數據混雜在一塊兒,代碼閱讀性差。指針