青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-381  評論-37  文章-0  trackbacks-0

拼包函數(shù)及網(wǎng)絡(luò)封包的異常處理(含代碼) 收藏
本文作者:sodme
本文出處:http://blog.csdn.net/sodme
聲明:本文可以不經(jīng)作者同意任意轉(zhuǎn)載、復(fù)制、傳播,但任何對本文的引用都請保留作者、出處及本聲明信息。謝謝!

  常見的網(wǎng)絡(luò)服務(wù)器,基本上是7*24小時運轉(zhuǎn)的,對于網(wǎng)游來說,至少要求服務(wù)器要能連續(xù)工作一周以上的時間并保證不出現(xiàn)服務(wù)器崩潰這樣的災(zāi)難性事件。事實上,要求一個服務(wù)器在連續(xù)的滿負荷運轉(zhuǎn)下不出任何異常,要求它設(shè)計的近乎完美,這幾乎是不太現(xiàn)實的。服務(wù)器本身可以出異常(但要盡可能少得出),但是,服務(wù)器本身應(yīng)該被設(shè)計得足以健壯,“小病小災(zāi)”打不垮它,這就要求服務(wù)器在異常處理方面要下很多功夫。

  服務(wù)器的異常處理包括的內(nèi)容非常廣泛,本文僅就在網(wǎng)絡(luò)封包方面出現(xiàn)的異常作一討論,希望能對正從事相關(guān)工作的朋友有所幫助。

  關(guān)于網(wǎng)絡(luò)封包方面的異常,總體來說,可以分為兩大類:一是封包格式出現(xiàn)異常;二是封包內(nèi)容(即封包數(shù)據(jù))出現(xiàn)異常。在封包格式的異常處理方面,我們在最底端的網(wǎng)絡(luò)數(shù)據(jù)包接收模塊便可以加以處理。而對于封包數(shù)據(jù)內(nèi)容出現(xiàn)的異常,只有依靠游戲本身的邏輯去加以判定和檢驗。游戲邏輯方面的異常處理,是隨每個游戲的不同而不同的,所以,本文隨后的內(nèi)容將重點闡述在網(wǎng)絡(luò)數(shù)據(jù)包接收模塊中的異常處理。

  為方便以下的討論,先明確兩個概念(這兩個概念是為了敘述方面,筆者自行取的,并無標準可言):
  1、邏輯包:指的是在應(yīng)用層提交的數(shù)據(jù)包,一個完整的邏輯包可以表示一個確切的邏輯意義。比如登錄包,它里面就可以含有用戶名字段和密碼字段。盡管它看上去也是一段緩沖區(qū)數(shù)據(jù),但這個緩沖區(qū)里的各個區(qū)間是代表一定的邏輯意義的。
  2、物理包:指的是使用recv(recvfrom)或wsarecv(wsarecvfrom)從網(wǎng)絡(luò)底層接收到的數(shù)據(jù)包,這樣收到的一個數(shù)據(jù)包,能不能表示一個完整的邏輯意義,要取決于它是通過UDP類的“數(shù)據(jù)報協(xié)議”發(fā)的包還是通過TCP類的“流協(xié)議”發(fā)的包。

  我們知道,TCP是流協(xié)議,“流協(xié)議”與“數(shù)據(jù)報協(xié)議”的不同點在于:“數(shù)據(jù)報協(xié)議”中的一個網(wǎng)絡(luò)包本身就是一個完整的邏輯包,也就是說,在應(yīng)用層使用sendto發(fā)送了一個邏輯包之后,在接收端通過recvfrom接收到的就是剛才使用sendto發(fā)送的那個邏輯包,這個包不會被分開發(fā)送,也不會與其它的包放在一起發(fā)送。但對于TCP而言,TCP會根據(jù)網(wǎng)絡(luò)狀況和neagle算法,或者將一個邏輯包單獨發(fā)送,或者將一個邏輯包分成若干次發(fā)送,或者會將若干個邏輯包合在一起發(fā)送出去。正因為TCP在邏輯包處理方面的這種粘合性,要求我們在作基于TCP的應(yīng)用時,一般都要編寫相應(yīng)的拼包、解包代碼。

  因此,基于TCP的上層應(yīng)用,一般都要定義自己的包格式。TCP的封包定義中,除了具體的數(shù)據(jù)內(nèi)容所代表的邏輯意義之外,第一步就是要確定以何種方式表示當(dāng)前包的開始和結(jié)束。通常情況下,表示一個TCP邏輯包的開始和結(jié)束有兩種方式:
  1、以特殊的開始和結(jié)束標志表示,比如FF00表示開始,00FF表示結(jié)束。
  2、直接以包長度來表示。比如可以用第一個字節(jié)表示包總長度,如果覺得這樣的話包比較小,也可以用兩個字節(jié)表示包長度。

  下面將要給出的代碼是以第2種方式定義的數(shù)據(jù)包,包長度以每個封包的前兩個字節(jié)表示。我將結(jié)合著代碼給出相關(guān)的解釋和說明。

  函數(shù)中用到的變量說明:

  CLIENT_BUFFER_SIZE:緩沖區(qū)的長度,定義為:Const int CLIENT_BUFFER_SIZE=4096。
  m_ClientDataBuf:數(shù)據(jù)整理緩沖區(qū),每次收到的數(shù)據(jù),都會先被復(fù)制到這個緩沖區(qū)的末尾,然后由下面的整理函數(shù)對這個緩沖區(qū)進行整理。它的定義是:char m_ClientDataBuf[2* CLIENT_BUFFER_SIZE]。
  m_DataBufByteCount:數(shù)據(jù)整理緩沖區(qū)中當(dāng)前剩余的未整理字節(jié)數(shù)。
  GetPacketLen(const char*):函數(shù),可以根據(jù)傳入的緩沖區(qū)首址按照應(yīng)用層協(xié)議取出當(dāng)前邏輯包的長度。
  GetGamePacket(const char*, int):函數(shù),可以根據(jù)傳入的緩沖區(qū)生成相應(yīng)的游戲邏輯數(shù)據(jù)包。
  AddToExeList(PBaseGamePacket):函數(shù),將指定的游戲邏輯數(shù)據(jù)包加入待處理的游戲邏輯數(shù)據(jù)包隊列中,等待邏輯處理線程對其進行處理。
  DATA_POS:指的是除了包長度、包類型等這些標志型字段之外,真正的數(shù)據(jù)包內(nèi)容的起始位置。

Bool SplitFun(const char* pData,const int &len)
{
    PBaseGamePacket pGamePacket=NULL;
    __int64 startPos=0, prePos=0, i=0;
    int packetLen=0;

  //先將本次收到的數(shù)據(jù)復(fù)制到整理緩沖區(qū)尾部
    startPos = m_DataBufByteCount; 
    memcpy( m_ClientDataBuf+startPos, pData, len );
    m_DataBufByteCount += len;   

    //當(dāng)整理緩沖區(qū)內(nèi)的字節(jié)數(shù)少于DATA_POS字節(jié)時,取不到長度信息則退出
 //注意:退出時并不置m_DataBufByteCount為0
    if (m_DataBufByteCount < DATA_POS+1)
        return false;

    //根據(jù)正常邏輯,下面的情況不可能出現(xiàn),為穩(wěn)妥起見,還是加上
    if (m_DataBufByteCount >  2*CLIENT_BUFFER_SIZE)
    {
        //設(shè)置m_DataBufByteCount為0,意味著丟棄緩沖區(qū)中的現(xiàn)有數(shù)據(jù)
        m_DataBufByteCount = 0;

  //可以考慮開放錯誤格式數(shù)據(jù)包的處理接口,處理邏輯交給上層
  //OnPacketError()
        return false;
    }

     //還原起始指針
     startPos = 0;

     //只有當(dāng)m_ClientDataBuf中的字節(jié)個數(shù)大于最小包長度時才能執(zhí)行此語句
    packetLen = GetPacketLen( pIOCPClient->m_ClientDataBuf );

    //當(dāng)邏輯層的包長度不合法時,則直接丟棄該包
    if ((packetLen < DATA_POS+1) || (packetLen > 2*CLIENT_BUFFER_SIZE))
    {
        m_DataBufByteCount = 0;

  //OnPacketError()
        return false;
    }

    //保留整理緩沖區(qū)的末尾指針
    __int64 oldlen = m_DataBufByteCount;

    while ((packetLen <= m_DataBufByteCount) && (m_DataBufByteCount>0))
    {
        //調(diào)用拼包邏輯,獲取該緩沖區(qū)數(shù)據(jù)對應(yīng)的數(shù)據(jù)包
        pGamePacket = GetGamePacket(m_ClientDataBuf+startPos, packetLen);

        if (pGamePacket!=NULL)
        {
            //將數(shù)據(jù)包加入執(zhí)行隊列
            AddToExeList(pGamePacket);
        }

        pGamePacket = NULL;
 
  //整理緩沖區(qū)的剩余字節(jié)數(shù)和新邏輯包的起始位置進行調(diào)整
        m_DataBufByteCount -= packetLen;
        startPos += packetLen;

        //殘留緩沖區(qū)的字節(jié)數(shù)少于一個正常包大小時,只向前復(fù)制該包隨后退出
        if (m_DataBufByteCount < DATA_POS+1)
        {
            for(i=startPos; i<startPos+m_DataBufByteCount; ++i)
                m_ClientDataBuf[i-startPos] = m_ClientDataBuf[i];

            return true;
        }

        packetLen = GetPacketLen(m_ClientDataBuf + startPos );

         //當(dāng)邏輯層的包長度不合法時,丟棄該包及緩沖區(qū)以后的包
        if ((packetLen<DATA_POS+1) || (packetLen>2*CLIENT_BUFFER_SIZE))
        {
            m_DataBufByteCount = 0;

      //OnPacketError()
            return false;
        }

         if (startPos+packetLen>=oldlen)
        {
            for(i=startPos; i<startPos+m_DataBufByteCount; ++i)
                m_ClientDataBuf[i-startPos] = m_ClientDataBuf[i];          

            return true;
        }
     }//取所有完整的包

     return true;
}

  以上便是數(shù)據(jù)接收模塊的處理函數(shù),下面是幾點簡要說明:

  1、用于拼包整理的緩沖區(qū)(m_ClientDataBuf)應(yīng)該比recv中指定的接收緩沖區(qū)(pData)長度(CLIENT_BUFFER_SIZE)要大,通常前者是后者的2倍(2*CLIENT_BUFFER_SIZE)或更大。

  2、為避免因為剩余數(shù)據(jù)前移而導(dǎo)致的額外開銷,建議m_ClientDataBuf使用環(huán)形緩沖區(qū)實現(xiàn)。

  3、為了避免出現(xiàn)無法拼裝的包,我們約定每次發(fā)送的邏輯包,其單個邏輯包最大長度不可以超過CLIENT_BUFFER_SIZE的2倍。因為我們的整理緩沖區(qū)只有2*CLIENT_BUFFER_SIZE這么長,更長的數(shù)據(jù),我們將無法整理。這就要求在協(xié)議的設(shè)計上以及最終的發(fā)送函數(shù)的處理上要加上這樣的異常處理機制。


  4、對于數(shù)據(jù)包過短或過長的包,我們通常的情況是置m_DataBufByteCount為0,即舍棄當(dāng)前包的處理。如果此處不設(shè)置m_DataBufByteCount為0也可,但該客戶端只要發(fā)了一次格式錯誤的包,則其后繼發(fā)過來的包則也將連帶著產(chǎn)生格式錯誤,如果設(shè)置m_DataBufByteCount為0,則可以比較好的避免后繼的包受此包的格式錯誤影響。更好的作法是,在此處開放一個封包格式異常的處理接口(OnPacketError),由上層邏輯決定對這種異常如何處置。比如上層邏輯可以對封包格式方面出現(xiàn)的異常進行計數(shù),如果錯誤的次數(shù)超過一定的值,則可以斷開該客戶端的連接。

  5、建議不要在recv或wsarecv的函數(shù)后,就緊接著作以上的處理。當(dāng)recv收到一段數(shù)據(jù)后,生成一個結(jié)構(gòu)體或?qū)ο?它主要含有data和len兩個內(nèi)容,前者是數(shù)據(jù)緩沖區(qū),后者是數(shù)據(jù)長度),將這樣的一個結(jié)構(gòu)體或?qū)ο蠓诺揭粋€隊列中由后面的線程對其使用SplitFun函數(shù)進行整理。這樣,可以最大限度地提高網(wǎng)絡(luò)數(shù)據(jù)的接收速度,不至因為數(shù)據(jù)整理的原因而在此處浪費時間。

  代碼中,我已經(jīng)作了比較詳細的注釋,可以作為拼包函數(shù)的參考,代碼是從偶的應(yīng)用中提取、修改而來,本身只為演示之用,所以未作調(diào)試,應(yīng)用時需要你自己去完善。如有疑問,可以我的blog上留言提出。


本文來自CSDN博客,轉(zhuǎn)載請標明出處:http://blog.csdn.net/clever101/archive/2008/10/12/3061679.aspx

posted on 2010-02-18 02:27 小王 閱讀(695) 評論(0)  編輯 收藏 引用 所屬分類: 網(wǎng)絡(luò)通訊
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久噜噜亚洲综合| 99这里有精品| 你懂的网址国产 欧美| 夜夜嗨av色一区二区不卡| 亚洲视频高清| 1769国产精品| 99www免费人成精品| 亚洲欧美一区二区三区极速播放| 久久av二区| 一区二区国产精品| 久久久久综合一区二区三区| 亚洲亚洲精品三区日韩精品在线视频| 久久国产精品72免费观看| 亚洲综合精品自拍| 欧美日韩hd| 欧美黄色免费| 一色屋精品视频在线看| 亚洲欧美激情四射在线日| 99亚洲一区二区| 国产精品无码永久免费888| 亚洲高清成人| 99xxxx成人网| 欧美在线国产| 久久尤物视频| 麻豆亚洲精品| 国内成人自拍视频| 翔田千里一区二区| 久久大逼视频| 99re6热只有精品免费观看| 久久在线免费观看视频| 艳女tv在线观看国产一区| 久久人人97超碰国产公开结果| 亚洲精品久久7777| 男同欧美伦乱| 欧美一区二区三区在线播放| 久久精品在线观看| 国内精品**久久毛片app| 欧美日韩国产综合网| 久久精品国产免费观看| 亚洲网站啪啪| 久久久99爱| 亚洲女爱视频在线| 国产手机视频一区二区| 久久精品国产99精品国产亚洲性色| 最新国产の精品合集bt伙计| 亚洲久久成人| 国产精品久久网| 午夜欧美大片免费观看| 亚洲精品综合精品自拍| 午夜日韩av| 99精品热视频只有精品10| 在线免费日韩片| 国产一区二区三区直播精品电影 | 亚洲人屁股眼子交8| 一本一本大道香蕉久在线精品| 一色屋精品视频免费看| 国产在线不卡| 国产日韩欧美一二三区| 国产精品三级久久久久久电影| 欧美精品日韩一本| 日韩午夜在线观看视频| 久久精品国产999大香线蕉| 亚洲国产精品电影| 国产精品入口麻豆原神| 国产精品九九久久久久久久| 亚洲欧美文学| 亚洲人成网站在线观看播放| 欧美激情中文不卡| 亚洲国产精品久久久久秋霞不卡| 午夜精品久久久久久99热软件| 一区二区三区国产| 夜久久久久久| 亚洲在线观看视频网站| 亚洲在线视频免费观看| 亚洲综合视频网| 欧美一区二区视频在线观看| 性亚洲最疯狂xxxx高清| 亚洲激情欧美| 国产酒店精品激情| 欧美激情精品久久久久久变态| 午夜精品久久久| 欧美一区二区三区久久精品茉莉花 | 亚洲第一成人在线| 亚洲大片免费看| 亚洲靠逼com| 亚洲午夜av| 久久成人羞羞网站| 久久综合色播五月| 欧美日韩妖精视频| 久久久久久久久蜜桃| 老色鬼久久亚洲一区二区| 农村妇女精品| 欧美午夜在线视频| 欧美电影在线观看| 久久夜色精品国产噜噜av| 小辣椒精品导航| 老司机免费视频一区二区三区| 欧美黄色精品| 国产精品一区三区| 亚洲国产二区| 亚洲摸下面视频| 免费成人av| 久久综合九色综合欧美就去吻 | 激情成人av在线| 国产美女在线精品免费观看| 激情成人综合| 中文av字幕一区| 日韩亚洲成人av在线| 欧美亚洲免费电影| 欧美国产日韩免费| 中文在线不卡视频| 另类综合日韩欧美亚洲| 久久精品夜色噜噜亚洲aⅴ| 久久精品国产欧美激情| 欧美日韩p片| 黄色成人在线网站| 亚洲成人资源| 亚洲欧美制服另类日韩| 欧美大片免费观看| 欧美成人精品在线观看| 美女主播一区| 亚洲一区二区三区欧美| 亚洲无吗在线| 欧美a级在线| 国产一区亚洲一区| 亚洲影院在线| 亚洲人成网站777色婷婷| 欧美自拍偷拍| 国产乱码精品一区二区三区不卡| 久久精品国产精品亚洲综合| 欧美va亚洲va日韩∨a综合色| 国产女人水真多18毛片18精品视频| 欧美日本乱大交xxxxx| 欧美日韩国产美女| 在线高清一区| 久久精品网址| 亚洲伊人观看| 国产精品久久久久婷婷| 99视频在线观看一区三区| 老鸭窝91久久精品色噜噜导演| 亚洲一区二区三区乱码aⅴ| 欧美日韩国产123区| 亚洲人成人一区二区三区| 中文国产一区| 亚洲精品裸体| 久热爱精品视频线路一| 国内激情久久| 久久乐国产精品| 午夜精品区一区二区三| 国产精品久久久久aaaa樱花| 一区二区冒白浆视频| 亚洲第一在线| 美日韩精品免费观看视频| 精品成人一区二区三区四区| 久久久7777| 欧美一区二区三区啪啪| 国产亚洲欧美日韩日本| 欧美在线亚洲一区| 午夜精品一区二区三区电影天堂 | 欧美在线二区| 国产精品一区二区在线| 午夜精品一区二区三区在线播放| 亚洲色图在线视频| 国产精品美女久久久久av超清 | 久久精品视频在线看| 欧美综合77777色婷婷| 狠狠久久亚洲欧美| 裸体一区二区| 免费观看日韩| 日韩网站免费观看| 日韩视频免费观看| 国产精品福利影院| 欧美一区永久视频免费观看| 午夜国产精品视频| 国内欧美视频一区二区| 久久五月激情| 欧美成人精品1314www| 日韩视频一区二区三区在线播放免费观看| 亚洲国产一区在线观看| 欧美日韩国产一区精品一区 | 久久久精品性| 免费成人av在线| 在线午夜精品自拍| 亚洲一区www| 激情久久婷婷| 日韩视频在线一区二区| 国产精品区一区| 开心色5月久久精品| 欧美国产亚洲视频| 亚洲欧美第一页| 久久精品主播| 亚洲另类在线视频| 亚洲一区二区三区高清 | 久久久av水蜜桃| 亚洲精品在线免费| 亚洲欧美成人网| 亚洲日本中文字幕| 亚洲欧美日韩一区二区三区在线| 亚洲成色777777在线观看影院| 日韩视频免费观看|