第二人生的源码分析(三十六)获取消息包里每一个字段

上面介绍了怎么样构造消息模板,并用它来灵活地生成各种各样需要传送数据的数据结构,现在就来分析一下使用模板怎么样去分析缓冲区里的数据,然后获取消息各个字段数据,这样才可以让别的程序使用起来。
#001 BOOL LLTemplateMessageReader::readMessage(const U8* buffer,
#002                                                                       const LLHost&
#003 sender)
#004 {
#005      return decodeData(buffer, sender);
#006 }
 
在LLMessageSystem::checkMessages函数里调用readMessage函数来解包,而函数readMessage又需要调用函数decodeData把缓冲区buffer里的数据分离出来,供其它的程序使用。下面就是函数decodeData的代码:
#001 // decode a given message
#002 BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender )
#003 {
#004      llassert( mReceiveSize >= 0 );
#005      llassert( mCurrentRMessageTemplate);
#006      llassert( !mCurrentRMessageData );
#007      delete mCurrentRMessageData; // just to make sure
#008 
 
下面的程序跳过包头数据,获取到真实的数据开始位置。
#009      // The offset tells us how may bytes to skip after the end of the
#010      // message name.
#011      U8 offset = buffer[PHL_OFFSET];
#012      S32 decode_pos = LL_PACKET_ID_SIZE + (S32)(mCurrentRMessageTemplate->mFrequency) + offset;
#013 
 
创建一个消息保存当前的数据字段。
#014      // create base working data set
#015      mCurrentRMessageData = new LLMsgData(mCurrentRMessageTemplate->mName);
#016     
 
下面通过消息的模板来获取缓冲区里每个字段的数据。
#017      // loop through the template building the data structure as we go
#018      LLMessageTemplate::message_block_map_t::const_iterator iter;
#019      for(iter = mCurrentRMessageTemplate->mMemberBlocks.begin();
#020             iter != mCurrentRMessageTemplate->mMemberBlocks.end();
#021             ++iter)
#022      {
#023             LLMessageBlock* mbci = *iter;
#024             U8   repeat_number;
#025             S32 i;
#026 
 
先根据模板查看有多少块数据。
#027             // how many of this block?
#028 
 
只有一块数据。
#029             if (mbci->mType == MBT_SINGLE)
#030             {
#031                    // just one
#032                    repeat_number = 1;
#033             }
 
多块数据。
#034             else if (mbci->mType == MBT_MULTIPLE)
#035             {
#036                    // a known number
#037                    repeat_number = mbci->mNumber;
#038             }
 
可变的数据块。
#039             else if (mbci->mType == MBT_VARIABLE)
#040             {
#041                    // need to read the number from the message
#042                    // repeat number is a single byte
#043                    if (decode_pos >= mReceiveSize)
#044                    {
#045                           logRanOffEndOfPacket(sender, decode_pos, 1);
#046 
#047                           // default to 0 repeats
#048                           repeat_number = 0;
#049                    }
#050                    else
#051                    {
#052                           repeat_number = buffer[decode_pos];
#053                           decode_pos++;
#054                    }
#055             }
 
没有定义的数据块。
#056             else
#057             {
#058                    llerrs << "Unknown block type" << llendl;
#059                    return FALSE;
#060             }
#061 
#062             LLMsgBlkData* cur_data_block = NULL;
#063 
 
 
下面开始循环分析数据块。
#064             // now loop through the block
#065             for (i = 0; i < repeat_number; i++)
#066             {
 
 
创建数据块结构保存数据。
#067                    if (i)
#068                    {
#069                           // build new name to prevent collisions
#070                           // TODO: This should really change to a vector
#071                           cur_data_block = new LLMsgBlkData(mbci->mName, repeat_number);
#072                           cur_data_block->mName = mbci->mName + i;
#073                    }
#074                    else
#075                    {
#076                           cur_data_block = new LLMsgBlkData(mbci->mName, repeat_number);
#077                    }
#078 
 
添加数据块到当前消息结构里。
#079                    // add the block to the message
#080                    mCurrentRMessageData->addBlock(cur_data_block);
#081 
 
开始根据消息模板的定义去分析缓冲区里每个字段。
#082                    // now read the variables
#083                    for (LLMessageBlock::message_variable_map_t::const_iterator iter =
#084                                   mbci->mMemberVariables.begin();
#085                            iter != mbci->mMemberVariables.end(); iter++)
#086                    {
#087                           const LLMessageVariable& mvci = **iter;
#088 
#089                           // ok, build out the variables
#090                           // add variable block
#091                           cur_data_block->addVariable(mvci.getName(), mvci.getType());
#092 
#093                           // what type of variable?
#094                           if (mvci.getType() == MVT_VARIABLE)
#095                           {
#096                                  // variable, get the number of bytes to read from the template
#097                                  S32 data_size = mvci.getSize();
#098                                  U8 tsizeb = 0;
#099                                  U16 tsizeh = 0;
#100                                  U32 tsize = 0;
#101 
#102                                  if ((decode_pos + data_size) > mReceiveSize)
#103                                  {
#104                                         logRanOffEndOfPacket(sender, decode_pos, data_size);
#105 
#106                                         // default to 0 length variable blocks
#107                                         tsize = 0;
#108                                  }
#109                                  else
#110                                  {
#111                                         switch(data_size)
#112                                         {
#113                                         case 1:
#114                                                htonmemcpy(&tsizeb, &buffer[decode_pos], MVT_U8, 1);
#115                                                tsize = tsizeb;
#116                                                break;
#117                                         case 2:
#118                                                htonmemcpy(&tsizeh, &buffer[decode_pos], MVT_U16, 2);
#119                                                tsize = tsizeh;
#120                                                break;
#121                                         case 4:
#122                                                htonmemcpy(&tsize, &buffer[decode_pos], MVT_U32, 4);
#123                                                break;
#124                                         default:
#125                                                llerrs << "Attempting to read variable field with unknown size of " <<
#126 data_size << llendl;
#127                                                break;
#128                                         }
#129                                  }
#130                                  decode_pos += data_size;
#131 
#132                                  cur_data_block->addData(mvci.getName(), &buffer[decode_pos], tsize, mvci.getType());
#133                                  decode_pos += tsize;
#134                           }
#135                           else
#136                           {
#137                                  // fixed!
#138                                  // so, copy data pointer and set data size to fixed size
#139                                  if ((decode_pos + mvci.getSize()) > mReceiveSize)
#140                                  {
#141                                         logRanOffEndOfPacket(sender, decode_pos, mvci.getSize());
#142 
#143                                         // default to 0s.
#144                                         U32 size = mvci.getSize();
#145                                         std::vector<U8> data(size);
#146                                         memset(&(data[0]), 0, size);
#147                                         cur_data_block->addData(mvci.getName(), &(data[0]),
#148                                                                           
#149      size, mvci.getType());
#150                                  }
#151                                  else
#152                                  {
#153                                         cur_data_block->addData(mvci.getName(),
#154                                                                           
#155      &buffer[decode_pos],
#156                                                                           
#157      mvci.getSize(),
#158                                                                           
#159      mvci.getType());
#160                                  }
#161                                  decode_pos += mvci.getSize();
#162                           }
#163                    }
#164             }
#165      }
#166 
 
数据块分析完成,后面就需要判断这个数据包是否分析合法。
#167      if (mCurrentRMessageData->mMemberBlocks.empty()
#168             && !mCurrentRMessageTemplate->mMemberBlocks.empty())
#169      {
#170             lldebugs << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << llendl;
#171             return FALSE;
#172      }
#173 
#174      {
#175             static LLTimer decode_timer;
#176 
#177             if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback())
#178             {
#179                    decode_timer.reset();
#180             }
#181 
#182             {
#183                    LLFastTimer t(LLFastTimer::FTM_PROCESS_MESSAGES);
#184                    if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) )
#185                    {
#186                           llwarns << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate-
#187 >mName << llendl;
#188                    }
#189             }
#190 
#191             if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback())
#192             {
#193                     F32 decode_time = decode_timer.getElapsedTimeF32();
#194 
#195                    if (gMessageSystem->getTimingCallback())
#196                    {
#197                           (gMessageSystem->getTimingCallback())(mCurrentRMessageTemplate->mName,
#198                                                       decode_time,
#199                                                       gMessageSystem->getTimingCallbackData());
#200                    }
#201 
#202                    if (LLMessageReader::getTimeDecodes())
#203                    {
#204                           mCurrentRMessageTemplate->mDecodeTimeThisFrame += decode_time;
#205 
#206                           mCurrentRMessageTemplate->mTotalDecoded++;
#207                           mCurrentRMessageTemplate->mTotalDecodeTime += decode_time;
#208 
#209                           if( mCurrentRMessageTemplate->mMaxDecodeTimePerMsg < decode_time )
#210                           {
#211                                  mCurrentRMessageTemplate->mMaxDecodeTimePerMsg = decode_time;
#212                           }
#213 
#214 
#215                           if(decode_time > LLMessageReader::getTimeDecodesSpamThreshold())
#216                           {
#217                                  lldebugs << "--------- Message " << mCurrentRMessageTemplate->mName << " decode took " <<
#218 decode_time << " seconds. (" <<
#219                                         mCurrentRMessageTemplate->mMaxDecodeTimePerMsg << " max, " <<
#220                                         (mCurrentRMessageTemplate->mTotalDecodeTime / mCurrentRMessageTemplate-
#221 >mTotalDecoded) << " avg)" << llendl;
#222                           }
#223                    }
#224             }
#225      }
#226      return TRUE;
#227 }
#228 
 
通过消息模板里的定义去解释缓冲区里的数据,然后就把这些字段加入到cur_data_block里,最后其它程序通过函数LLTemplateMessageReader::getData来获取这个消息的字段数据,这样就达到第二人生客户端与服务器交流的目的。 
posted @ 2008-04-14 21:53  ajuanabc  阅读(147)  评论(0)    收藏  举报