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

每天早晨叫醒你的不是鬧鐘,而是夢(mèng)想

  C++博客 :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
  62 Posts :: 0 Stories :: 5 Comments :: 0 Trackbacks

常用鏈接

留言簿(1)

我參與的團(tuán)隊(duì)

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

作者:fengge8ylf  博客:http://blog.csdn.net/fengge8ylf

對(duì)于基于TCP開(kāi)發(fā)的通訊程序,有個(gè)很重要的問(wèn)題需要解決,就是封包和拆包.自從我從事網(wǎng)絡(luò)通訊編程工作以來(lái)(大概有三年的時(shí)間了),我一直在思索和改進(jìn)封包和拆包的方法.下面就針對(duì)這個(gè)問(wèn)題談?wù)勎业南敕?拋磚引玉.若有不對(duì),不妥之處,懇求大家指正.在此先謝過(guò)大家了.

一.為什么基于TCP的通訊程序需要進(jìn)行封包和拆包.

TCP是個(gè)"流"協(xié)議,所謂流,就是沒(méi)有界限的一串?dāng)?shù)據(jù).大家可以想想河里的流水,是連成一片的,其間是沒(méi)有分界線的.但一般通訊程序開(kāi)發(fā)是需要定義一個(gè)個(gè)相互獨(dú)立的數(shù)據(jù)包的,比如用于登陸的數(shù)據(jù)包,用于注銷(xiāo)的數(shù)據(jù)包.由于TCP"流"的特性以及網(wǎng)絡(luò)狀況,在進(jìn)行數(shù)據(jù)傳輸時(shí)會(huì)出現(xiàn)以下幾種情況.
假設(shè)我們連續(xù)調(diào)用兩次send分別發(fā)送兩段數(shù)據(jù)data1和data2,在接收端有以下幾種接收情況(當(dāng)然不止這幾種情況,這里只列出了有代表性的情況).
A.先接收到data1,然后接收到data2.
B.先接收到data1的部分?jǐn)?shù)據(jù),然后接收到data1余下的部分以及data2的全部.
C.先接收到了data1的全部數(shù)據(jù)和data2的部分?jǐn)?shù)據(jù),然后接收到了data2的余下的數(shù)據(jù).
D.一次性接收到了data1和data2的全部數(shù)據(jù).

對(duì)于A這種情況正是我們需要的,不再做討論.對(duì)于B,C,D的情況就是大家經(jīng)常說(shuō)的"粘包",就需要我們把接收到的數(shù)據(jù)進(jìn)行拆包,拆成一個(gè)個(gè)獨(dú)立的數(shù)據(jù)包.為了拆包就必須在發(fā)送端進(jìn)行封包.
 另:對(duì)于UDP來(lái)說(shuō)就不存在拆包的問(wèn)題,因?yàn)閁DP是個(gè)"數(shù)據(jù)包"協(xié)議,也就是兩段數(shù)據(jù)間是有界限的,在接收端要么接收不到數(shù)據(jù)要么就是接收一個(gè)完整的一段數(shù)據(jù),不會(huì)少接收也不會(huì)多接收.

二.為什么會(huì)出現(xiàn)B.C.D的情況.
 "粘包"可發(fā)生在發(fā)送端也可發(fā)生在接收端.
 1.由Nagle算法造成的發(fā)送端的粘包:Nagle算法是一種改善網(wǎng)絡(luò)傳輸效率的算法.簡(jiǎn)單的說(shuō),當(dāng)我們提交一段數(shù)據(jù)給TCP發(fā)送時(shí),TCP并不立刻發(fā)送此段數(shù)據(jù),而是等待一小段時(shí)間,看看在等待期間是否還有要發(fā)送的數(shù)據(jù),若有則會(huì)一次把這兩段數(shù)據(jù)發(fā)送出去.這是對(duì)Nagle算法一個(gè)簡(jiǎn)單的解釋,詳細(xì)的請(qǐng)看相關(guān)書(shū)籍.象C和D的情況就有可能是Nagle算法造成的.
        2.接收端接收不及時(shí)造成的接收端粘包:TCP會(huì)把接收到的數(shù)據(jù)存在自己的緩沖區(qū)中,然后通知應(yīng)用層取數(shù)據(jù).當(dāng)應(yīng)用層由于某些原因不能及時(shí)的把TCP的數(shù)據(jù)取出來(lái),就會(huì)造成TCP緩沖區(qū)中存放了幾段數(shù)據(jù).

三.怎樣封包和拆包.
   最初遇到"粘包"的問(wèn)題時(shí),我是通過(guò)在兩次send之間調(diào)用sleep來(lái)休眠一小段時(shí)間來(lái)解決.這個(gè)解決方法的缺點(diǎn)是顯而易見(jiàn)的,使傳輸效率大大降低,而且也并不可靠.后來(lái)就是通過(guò)應(yīng)答的方式來(lái)解決,盡管在大多數(shù)時(shí)候是可行的,但是不能解決象B的那種情況,而且采用應(yīng)答方式增加了通訊量,加重了網(wǎng)絡(luò)負(fù)荷(但是象FTP等協(xié)議采用的就是應(yīng)答方式).再后來(lái)就是對(duì)數(shù)據(jù)包進(jìn)行封包和拆包的操作.
    封包:
 封包就是給一段數(shù)據(jù)加上包頭,這樣一來(lái)數(shù)據(jù)包就分為包頭和包體兩部分內(nèi)容了(以后講過(guò)濾非法包時(shí)封包會(huì)加入"包尾"內(nèi)容).包頭其實(shí)上是個(gè)大小固定的結(jié)構(gòu)體,其中有個(gè)結(jié)構(gòu)體成員變量表示包體的長(zhǎng)度,這是個(gè)很重要的變量,其他的結(jié)構(gòu)體成員可根據(jù)需要自己定義.根據(jù)包頭長(zhǎng)度固定以及包頭中含有包體長(zhǎng)度的變量就能正確的拆分出一個(gè)完整的數(shù)據(jù)包.
    對(duì)于拆包目前我最常用的是以下兩種方式.
    1.動(dòng)態(tài)緩沖區(qū)暫存方式.之所以說(shuō)緩沖區(qū)是動(dòng)態(tài)的是因?yàn)楫?dāng)需要緩沖的數(shù)據(jù)長(zhǎng)度超出緩沖區(qū)的長(zhǎng)度時(shí)會(huì)增大緩沖區(qū)長(zhǎng)度.
    大概過(guò)程描述如下:
    A,為每一個(gè)連接動(dòng)態(tài)分配一個(gè)緩沖區(qū),同時(shí)把此緩沖區(qū)和SOCKET關(guān)聯(lián),常用的是通過(guò)結(jié)構(gòu)體關(guān)聯(lián).
    B,當(dāng)接收到數(shù)據(jù)時(shí)首先把此段數(shù)據(jù)存放在緩沖區(qū)中.
    C,判斷緩存區(qū)中的數(shù)據(jù)長(zhǎng)度是否夠一個(gè)包頭的長(zhǎng)度,如不夠,則不進(jìn)行拆包操作.
    D,根據(jù)包頭數(shù)據(jù)解析出里面代表包體長(zhǎng)度的變量.
    E,判斷緩存區(qū)中除包頭外的數(shù)據(jù)長(zhǎng)度是否夠一個(gè)包體的長(zhǎng)度,如不夠,則不進(jìn)行拆包操作.
    F,取出整個(gè)數(shù)據(jù)包.這里的"取"的意思是不光從緩沖區(qū)中拷貝出數(shù)據(jù)包,而且要把此數(shù)據(jù)包從緩存區(qū)中刪除掉.刪除的辦法就是把此包后面的數(shù)據(jù)移動(dòng)到緩沖區(qū)的起始地址.

    這種方法有兩個(gè)缺點(diǎn).1.為每個(gè)連接動(dòng)態(tài)分配一個(gè)緩沖區(qū)增大了內(nèi)存的使用.2.有三個(gè)地方需要拷貝數(shù)據(jù),一個(gè)地方是把數(shù)據(jù)存放在緩沖區(qū),一個(gè)地方是把完整的數(shù)據(jù)包從緩沖區(qū)取出來(lái),一個(gè)地方是把數(shù)據(jù)包從緩沖區(qū)中刪除.這種拆包的改進(jìn)方法會(huì)解決和完善部分缺點(diǎn).

    下面給出相關(guān)代碼.

先看包頭結(jié)構(gòu)定義

 

 1 #pragma pack(push,1//開(kāi)始定義數(shù)據(jù)包, 采用字節(jié)對(duì)齊方式
 2 /*----------------------包頭---------------------*/
 3 typedef struct tagPACKAGEHEAD
 4 {
 5  BYTE Version;
 6  WORD Command;
 7  WORD nDataLen;//包體的長(zhǎng)度
 8 }PACKAGE_HEAD;
 9 #pragma pack(pop) //結(jié)束定義數(shù)據(jù)包, 恢復(fù)原來(lái)對(duì)齊方式 
10 
11 然后看存放數(shù)據(jù)和""數(shù)據(jù)函數(shù).
12 
13 /*****************************************************************************
14 Description:添加數(shù)據(jù)到緩存
15 Input:pBuff[in]-待添加的數(shù)據(jù);nLen[in]-待添加數(shù)據(jù)長(zhǎng)度
16 Return: 如果當(dāng)前緩沖區(qū)沒(méi)有足夠的空間存放pBuff則返回FALSE;否則返回TRUE。
17 ******************************************************************************/
18 BOOL CDataBufferPool::AddBuff( char *pBuff, int nLen )
19 {
20  m_cs.Lock();///臨界區(qū)鎖
21 
22  if ( nLen < 0 )
23  {
24   m_cs.Unlock();
25   return FALSE;
26  }
27 
28  if ( nLen <= GetFreeSize() )///判斷剩余空間是否足夠存放nLen長(zhǎng)的數(shù)據(jù)
29  {
30   memcpy(m_pBuff + m_nOffset, pBuff, nLen);
31   m_nOffset += nLen;
32  }
33  else///若不夠則擴(kuò)充原有的空間
34  { 
35   char *= m_pBuff;
36   m_nSize += nLen*2;//每次增長(zhǎng)2*nLen
37   m_pBuff = new char[m_nSize];
38   memcpy(m_pBuff,p,m_nOffset);
39   delete []p;
40   memcpy(m_pBuff + m_nOffset, pBuff, nLen);
41   m_nOffset += nLen;
42   m_cs.Unlock();
43   return FALSE;
44  }
45  m_cs.Unlock();
46  return TRUE;
47 }
48 
49  
50 
51 /*****************************************************************************
52 Description:獲取一個(gè)完整的包
53 Input:Buf[out]-獲取到的數(shù)據(jù);nLen[out]-獲取到的數(shù)據(jù)長(zhǎng)度
54 Return: 1、當(dāng)前緩沖區(qū)不夠一個(gè)包頭的數(shù)據(jù) 2、當(dāng)前緩沖區(qū)不夠一個(gè)包體的數(shù)據(jù)
55 ******************************************************************************/
56 
57 int  CDataBufferPool::GetFullPacket( char *Buf, int& nLen )
58 {
59  m_cs.Lock();
60 
61  if ( m_nOffset < m_PacketHeadLen )//當(dāng)前緩沖區(qū)不夠一個(gè)包頭的數(shù)據(jù)
62  {
63   m_cs.Unlock();
64   return 1;
65  }
66  PACKAGE_HEAD *= (PACKAGE_HEAD *)m_pBuff;
67  if( (m_nOffset-m_PacketHeadLen) < (int)p->nDataLen )//當(dāng)前緩沖區(qū)不夠一個(gè)包體的數(shù)據(jù)
68  {
69   m_cs.Unlock();
70   return 2;
71  }
72  //判斷包的合法性
73 /* int IsIntegrallity = ValidatePackIntegrality(p);
74  if( IsIntegrallity != 0 )
75  {
76   m_cs.Unlock();
77   return IsIntegrallity;
78  }
79 */
80  nLen = m_PacketHeadLen+p->nDataLen;
81  memcpy( Buf, m_pBuff, nLen );
82  m_nOffset -= nLen;
83  memcpy( m_pBuff, m_pBuff+nLen, m_nOffset );
84 
85  m_cs.Unlock();
86  return 0;
87 }
88 
89 


    前面提到過(guò)這種方法的缺點(diǎn).下面給出一個(gè)改進(jìn)辦法, 即采用環(huán)形緩沖.但是這種改進(jìn)方法還是不能解決第一個(gè)缺點(diǎn)以及第一個(gè)數(shù)據(jù)拷貝,只能解決第三個(gè)地方的數(shù)據(jù)拷貝(這個(gè)地方是拷貝數(shù)據(jù)最多的地方).第2種拆包方式會(huì)解決這兩個(gè)問(wèn)題.
 環(huán)形緩沖實(shí)現(xiàn)方案是定義兩個(gè)指針,分別指向有效數(shù)據(jù)的頭和尾.在存放數(shù)據(jù)和刪除數(shù)據(jù)時(shí)只是進(jìn)行頭尾指針的移動(dòng).
 用代碼來(lái)說(shuō)明.注:下面的代碼是采用一個(gè)開(kāi)源的游戲服務(wù)器的代碼,我對(duì)此代碼有所修改.
 

  1 int CCircularBufferPool::PutData(TCHAR *pData, int len)
  2 {
  3  if( len <= 0 ) 
  4   return 1;
  5 
  6  EnterCriticalSection(&m_cs);
  7  while (IsOverFlowCondition(len))///判斷緩沖區(qū)剩余空間是否夠存放len長(zhǎng)的數(shù)據(jù)
  8  {
  9   BufferResize(len);///若不夠,則擴(kuò)充緩沖區(qū).
 10  }
 11 
 12  if (IsIndexOverFlow(len))///判斷"尾"指針的位置.
 13  {
 14   int FirstCopyLen = m_iBufSize-m_iTailPos;
 15   int SecondCopyLen = len - FirstCopyLen;
 16   CopyMemory(m_pBuffer+m_iTailPos, pData, FirstCopyLen);
 17   if (SecondCopyLen)
 18   {
 19    CopyMemory(m_pBuffer, pData+FirstCopyLen, SecondCopyLen);
 20    m_iTailPos = SecondCopyLen;
 21   }
 22   else 
 23    m_iTailPos = 0;
 24  }
 25  else
 26  {
 27   CopyMemory(m_pBuffer+m_iTailPos, pData, len);
 28   m_iTailPos += len;
 29  }
 30 
 31  LeaveCriticalSection(&m_cs);
 32  return 0;
 33 
 34 
 35 }
 36 
 37 
 38 void CCircularBufferPool::GetData(TCHAR *pData, int len, bool Delete)
 39 {
 40  if (len < m_iBufSize-m_iHeadPos)
 41  {
 42   CopyMemory(pData, m_pBuffer+m_iHeadPos, len);
 43   if(Delete==true)
 44    m_iHeadPos += len;
 45  }
 46  else
 47  {
 48   int fc, sc;
 49   fc = m_iBufSize-m_iHeadPos;
 50   sc = len - fc;
 51   CopyMemory(pData, m_pBuffer+m_iHeadPos, fc);
 52   if (sc) CopyMemory(pData+fc, m_pBuffer, sc);
 53   if(Delete==true)
 54    m_iHeadPos = sc;
 55   if(m_iHeadPos >= m_iBufSize)
 56    m_iHeadPos = 0;
 57 
 58  }
 59 }
 60 
 61 //
 62 //進(jìn)行自定義包的解析
 63 //
 64 int CCircularBufferPool::GetFullPacket( TCHAR *Buf, int &nLen )
 65 {
 66  EnterCriticalSection(&m_cs);
 67  if( GetValidCount() < m_PacketHeadLen )//當(dāng)前緩沖區(qū)不夠一個(gè)包頭的數(shù)據(jù)
 68  {
 69   LeaveCriticalSection(&m_cs);
 70   return 1;
 71  }
 72 
 73  GetData(Buf,m_PacketHeadLen,false);
 74  PACKAGE_HEAD *= (PACKAGE_HEAD *)Buf;
 75  if( (GetValidCount()-m_PacketHeadLen) < (int)p->nDataLen )//當(dāng)前緩沖區(qū)不夠一個(gè)包體的數(shù)據(jù)
 76  {
 77   LeaveCriticalSection(&m_cs);
 78   return 2;
 79  }
 80 
 81  //判斷包的合法性
 82  int IsIntegrallity = ValidatePackIntegrality(p);
 83  if( IsIntegrallity != 0 )
 84  {
 85   LeaveCriticalSection(&m_cs);
 86   return IsIntegrallity;
 87  }
 88  
 89  GetData(Buf,m_PacketHeadLen+p->nDataLen,true);
 90  nLen = m_PacketHeadLen+p->nDataLen;
 91 
 92  LeaveCriticalSection(&m_cs);
 93 
 94 
 95  return 0;
 96 }
 97 
 98  2.利用底層的緩沖區(qū)來(lái)進(jìn)行拆包
 99  由于TCP也維護(hù)了一個(gè)緩沖區(qū),所以我們完全可以利用TCP的緩沖區(qū)來(lái)緩存我們的數(shù)據(jù),這樣一來(lái)就不需要為每一個(gè)連接分配一個(gè)緩沖區(qū)了.另一方面我們知道recv或者wsarecv都有一個(gè)參數(shù),用來(lái)表示我們要接收多長(zhǎng)長(zhǎng)度的數(shù)據(jù).利用這兩個(gè)條件我們就可以對(duì)第一種方法進(jìn)行優(yōu)化了.
100       對(duì)于阻塞SOCKET來(lái)說(shuō),我們可以利用一個(gè)循環(huán)來(lái)接收包頭長(zhǎng)度的數(shù)據(jù),然后解析出代表包體長(zhǎng)度的那個(gè)變量,再用一個(gè)循環(huán)來(lái)接收包體長(zhǎng)度的數(shù)據(jù).
101  相關(guān)代碼如下:
102    
103  char PackageHead[1024];
104  char PackageContext[1024*20];
105 
106  int len;
107  PACKAGE_HEAD *pPackageHead;
108  while( m_bClose == false )
109  {
110   memset(PackageHead,0,sizeof(PACKAGE_HEAD));
111   len = m_TcpSock.ReceiveSize((char*)PackageHead,sizeof(PACKAGE_HEAD));
112   if( len == SOCKET_ERROR )
113   {
114       break;
115   }
116   if(len == 0)
117   {
118       break;
119   }
120   pPackageHead = (PACKAGE_HEAD *)PackageHead;
121   memset(PackageContext,0,sizeof(PackageContext));
122   if(pPackageHead->nDataLen>0)
123   {
124    len = m_TcpSock.ReceiveSize((char*)PackageContext,pPackageHead->nDataLen);
125   }
126         }
127 
128  m_TcpSock是一個(gè)封裝了SOCKET的類(lèi)的變量,其中的ReceiveSize用于接收一定長(zhǎng)度的數(shù)據(jù),直到接收了一定長(zhǎng)度的數(shù)據(jù)或者網(wǎng)絡(luò)出錯(cuò)才返回.
129  
130 int winSocket::ReceiveSize( char* strData, int iLen )
131 {
132  if( strData == NULL )
133   return ERR_BADPARAM;
134  char *= strData;
135  int len = iLen;
136  int ret = 0;
137  int returnlen = 0;
138  while( len > 0)
139  {
140   ret = recv( m_hSocket, p+(iLen-len), iLen-returnlen, 0 );
141   if ( ret == SOCKET_ERROR || ret == 0 )
142   {
143    
144    return ret;
145   }
146 
147   len -= ret;
148   returnlen += ret;
149  }
150  
151  return returnlen;
152 }
153 
154 


 

 對(duì)于非阻塞的SOCKET,比如完成端口,我們可以提交接收包頭長(zhǎng)度的數(shù)據(jù)的請(qǐng)求,當(dāng)GetQueuedCompletionStatus返回時(shí),我們判斷接收的數(shù)據(jù)長(zhǎng)度是否等于包頭長(zhǎng)度,若等于,則提交接收包體長(zhǎng)度的數(shù)據(jù)的請(qǐng)求,若不等于則提交接收剩余數(shù)據(jù)的請(qǐng)求.當(dāng)接收包體時(shí),采用類(lèi)似的方法.
 下面給出相關(guān)代碼.

 1 enum IOType 
 2 {
 3  IOInitialize,
 4  IORead,
 5  IOWrite,
 6  IOIdle
 7 };
 8 
 9 class OVERLAPPEDPLUS 
10 {
11 public:
12  OVERLAPPED   m_ol;
13  IOType    m_ioType;
14  bool         m_bIsPackageHead;//當(dāng)前接收的數(shù)據(jù)是否是包頭數(shù)據(jù)。
15 
16  int          m_count;
17  WSABUF       m_wsaBuffer;
18  int          m_RecvPos;
19  char         m_Buffer[1024*8];//此緩沖要盡可能大
20 
21  OVERLAPPEDPLUS(IOType ioType) {
22   ZeroMemory(thissizeof(OVERLAPPEDPLUS));
23   m_ioType = ioType;
24  }
25 };
26 
27 

 

接收連接后發(fā)出的第一個(gè)請(qǐng)求,請(qǐng)求接收包頭大小的數(shù)據(jù).
 

 1 OVERLAPPEDPLUS *pOverlappedPlus =  new OVERLAPPEDPLUS;
 2  pOverlappedPlus->m_wsaBuffer.buf =  pOverlappedPlus->m_Buffer;
 3  pOverlappedPlus->m_wsaBuffer.len =  PACKAGE_HEAD_LEN;///包頭的長(zhǎng)度
 4  pOverlappedPlus->m_bIsPackageHead = true;
 5  pOverlappedPlus->m_RecvPos = 0;
 6  pOverlappedPlus->m_ioType = IORead;
 7 
 8 
 9  DWORD RecvBytes;
10      DWORD Flags;
11  Flags = 0;
12  if (WSARecv(clientSocket, &(pOverlappedPlus->m_wsaBuffer), 1&RecvBytes, &Flags,
13   &pOverlappedPlus->m_ol, NULL) == SOCKET_ERROR)
14  {
15   if (WSAGetLastError() != ERROR_IO_PENDING)
16   {
17    delete pOverlappedPlus;
18   }
19   else
20   {
21    ///相關(guān)的錯(cuò)誤處理
22 
23   }
24  }
25  else
26  {
27   ///相關(guān)的錯(cuò)誤處理
28 
29  }
30 
31 


在GetQueuedCompletionStatus所在的函數(shù)中.

 1 if( pOverlapPlus->m_ioType== IORead)
 2  { 
 3   if( pOverlapPlus->m_wsaBuffer.len == dwIoSize )
 4   {
 5    if( pOverlapPlus->m_bIsPackageHead == true )///接收到的是包頭。
 6    {
 7     PACKAGE_HEAD *pPackageHead = (PACKAGE_HEAD *)(pOverlapPlus->m_Buffer);
 8 
 9     if(pThis->IsLegalityPackageHead(pPackageHead)==false)///判斷是否是合法的包
10     {
11      closesocket(lpClientContext->m_Socket);
12      continue;
13     }
14 
15     pOverlapPlus->m_bIsPackageHead = false;
16     pOverlapPlus->m_wsaBuffer.len = pPackageHead->nDataLen;
17     pOverlapPlus->m_RecvPos += dwIoSize;
18     pOverlapPlus->m_wsaBuffer.buf = pOverlapPlus->m_Buffer+pOverlapPlus->m_RecvPos;
19 
20    }
21    else///接收到的是包體
22    {
23 
24      
25 
26    pOverlapPlus->m_RecvPos += dwIoSize;
27    ///這時(shí)pOverlapPlus->m_Buffer里就存放了一個(gè)完整的數(shù)據(jù)包,長(zhǎng)度為pOverlapPlus->m_RecvPos
28    
29 
30    ///繼續(xù)請(qǐng)求 請(qǐng)求下一個(gè)數(shù)據(jù)包的包頭
31    pOverlapPlus->m_wsaBuffer.buf =  pOverlapPlus->m_Buffer;
32    memset(pOverlapPlus->m_Buffer,0,sizeof(pOverlapPlus->m_Buffer));
33    pOverlapPlus->m_wsaBuffer.len =  PACKAGE_HEAD_LEN;
34    pOverlapPlus->m_bIsPackageHead = true;
35    pOverlapPlus->m_RecvPos = 0;
36      
37    }
38   }
39   else///接收的數(shù)據(jù)還不完整
40   {
41    pOverlapPlus->m_wsaBuffer.len -= dwIoSize;
42    pOverlapPlus->m_RecvPos += dwIoSize;
43    pOverlapPlus->m_wsaBuffer.buf = pOverlapPlus->m_Buffer+pOverlapPlus->m_RecvPos;
44   }
45   pOverlapPlus->m_ioType = IORead;
46   state = WSARecv(lpClientContext->m_Socket, &(pOverlapPlus->m_wsaBuffer), 1&RecvBytes, &Flags,
47     &pOverlapPlus->m_ol, NULL);
48   if ( state == SOCKET_ERROR)
49   {
50    if(WSAGetLastError() != ERROR_IO_PENDING)
51    {
52        
53        //關(guān)閉套接字 釋放相應(yīng)資源
54      continue;
55    }
56   }
57    
58  }
59 
60 


 三:如何判斷包的合法性.
判斷包的合法性可以結(jié)合下面兩種方式來(lái)判斷.但是想100%的判定出非法包,只能通過(guò)信息安全中的知識(shí)來(lái)判定了,對(duì)這種方法這里不做闡述.
1.通過(guò)包頭的結(jié)構(gòu)來(lái)判斷包的合法性.
 最初的時(shí)候我是根據(jù)包頭來(lái)判斷包的合法性,比如判斷Command是否超出命令范圍,nDataLen是否大于最大包的長(zhǎng)度.但是這種方法無(wú)法過(guò)濾掉非法包,當(dāng)出現(xiàn)非法包時(shí)我們唯一能做的就是斷開(kāi)連接,或許這也是最好的處理辦法.
 我們可以給一個(gè)完整的包加上開(kāi)始和結(jié)束標(biāo)志,標(biāo)志可以是個(gè)整數(shù),也可以是一串字符串.以第一種拆包方式為例來(lái)說(shuō)明.當(dāng)要拆一個(gè)完整包時(shí)我們先從緩沖區(qū)有效數(shù)據(jù)頭指針地址搜索包的開(kāi)始標(biāo)志,搜索到后并且當(dāng)前數(shù)據(jù)夠一個(gè)包頭數(shù)據(jù),則判斷開(kāi)始標(biāo)志和包頭是否合法,若合法則根據(jù)代表數(shù)據(jù)長(zhǎng)度的變量的值定位到包尾,判斷包尾標(biāo)志是否與我們定義的一致,若一致則這個(gè)包是合法的包.若有一項(xiàng)不一致則繼續(xù)尋找下個(gè)包的開(kāi)始標(biāo)志,并把下個(gè)合法包的前面的數(shù)據(jù)全部舍棄.
2.通過(guò)邏輯層來(lái)判斷包的合法性.
 當(dāng)取出一個(gè)合法的包時(shí),我們還要根據(jù)當(dāng)前數(shù)據(jù)處理的邏輯來(lái)判斷包的合法性.比如說(shuō)在登陸成功后的某段時(shí)間服務(wù)器又收到了同一個(gè)客戶端的登陸包,那我們就可以判斷這個(gè)包是非法的,簡(jiǎn)單處理就是斷開(kāi)連接.

posted on 2011-05-13 13:26 沛沛 閱讀(874) 評(píng)論(1)  編輯 收藏 引用 所屬分類(lèi): 網(wǎng)絡(luò)

Feedback

# re: 封包和拆包 2011-05-14 09:22 K.V
看到了。有用到但研究不深,Mark。  回復(fù)  更多評(píng)論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美成人精品1314www| 久久这里只有精品视频首页| 亚洲欧美日韩精品一区二区| 亚洲国产精品久久91精品| 久久久精品免费视频| 国产欧美精品在线播放| 亚洲影院色无极综合| 一本色道久久88精品综合| 欧美精品在线观看一区二区| 亚洲精品中文字幕在线| 亚洲国产乱码最新视频| 欧美精品aa| 艳妇臀荡乳欲伦亚洲一区| 亚洲人成在线观看| 欧美久久久久中文字幕| 亚洲无线视频| 亚洲私人影院| 国产美女精品一区二区三区| 久久精品91久久久久久再现| 欧美一区二区三区成人 | 欧美黄色aaaa| 裸体歌舞表演一区二区| 亚洲伦理久久| 制服丝袜亚洲播放| 国产一区二区三区免费在线观看| 久久女同互慰一区二区三区| 麻豆精品传媒视频| 一区二区三区在线观看视频| 欧美bbbxxxxx| 欧美日韩一区二区精品| 欧美一区二区三区日韩| 久久精品一二三区| 一本一本久久a久久精品综合妖精| 日韩午夜在线电影| 国产在线一区二区三区四区| 亚洲经典在线看| 欧美亚洲不卡| 欧美暴力喷水在线| 欧美日韩你懂的| 欧美一区二区三区免费在线看| 久久久不卡网国产精品一区| 一区二区免费在线观看| 性欧美videos另类喷潮| 日韩一级黄色片| 性欧美大战久久久久久久免费观看| 91久久精品国产91久久性色tv| 99精品视频免费在线观看| 国产午夜一区二区三区| 亚洲国产二区| 狠狠色综合网| 一区二区三区国产| 在线欧美影院| 亚洲欧美日韩在线| 欧美chengren| 国产农村妇女精品一区二区| 欧美国产综合一区二区| 国产精品中文字幕欧美| 亚洲电影视频在线| 国语自产精品视频在线看一大j8 | 在线色欧美三级视频| 亚洲午夜精品网| 亚洲精品一区二区网址| 午夜久久美女| 亚洲欧美日韩在线| 欧美日韩国产亚洲一区 | 伊人影院久久| 性色av香蕉一区二区| 日韩亚洲综合在线| 米奇777超碰欧美日韩亚洲| 久久精品亚洲热| 国产美女高潮久久白浆| 亚洲欧美国产精品桃花| 午夜性色一区二区三区免费视频| 欧美啪啪成人vr| 欧美电影免费观看| 亚洲国产天堂网精品网站| 久久久久久夜精品精品免费| 久久久久久综合| 国产视频亚洲| 久久高清免费观看| 久久人人超碰| 亚洲高清资源综合久久精品| 久久久久久91香蕉国产| 免费视频最近日韩| 亚洲国产一区二区三区高清| 久久尤物视频| 欧美成年人视频| 亚洲第一综合天堂另类专| 麻豆久久精品| 亚洲国产高清在线| 在线亚洲欧美视频| 国产精品美女视频网站| 先锋影院在线亚洲| 久久人人看视频| 亚洲国产精品一区二区第一页 | 欧美成年人网站| 狠狠色狠狠色综合日日tαg| 亚洲图片自拍偷拍| 久久久爽爽爽美女图片| 在线激情影院一区| 欧美激情精品久久久久久大尺度| 亚洲精品在线观看免费| 一本大道久久a久久精品综合| 欧美日韩国产在线观看| 亚洲一区二区在线| 奶水喷射视频一区| 亚洲一区bb| 国内一区二区在线视频观看 | 欧美成人一区在线| 99视频精品| 国产婷婷色一区二区三区在线 | 久久成人精品| 亚洲人成网站精品片在线观看| 欧美精品久久久久久久| 亚洲一区图片| 欧美 亚欧 日韩视频在线| 亚洲伦理在线免费看| 亚洲麻豆av| 国产真实乱偷精品视频免| 免费试看一区| 亚洲一本视频| 欧美1区3d| 亚洲欧美日韩一区二区三区在线观看| 国产自产高清不卡| 欧美图区在线视频| 久久久久一区二区| 亚洲一级电影| 亚洲精选在线| 欧美承认网站| 狼人天天伊人久久| 午夜在线不卡| 一区二区三欧美| 亚洲国产成人精品久久| 国产乱子伦一区二区三区国色天香| 免费在线播放第一区高清av| 亚洲中字在线| 一区二区欧美激情| 亚洲欧洲视频| 亚洲第一天堂av| 麻豆精品在线观看| 久久久国产91| 亚洲男人影院| 一区二区免费看| 亚洲精品国产欧美| 激情久久综合| 国产亚洲精品v| 国产精品视频999| 欧美日韩免费在线观看| 欧美精品精品一区| 欧美精品久久久久a| 免费日韩成人| 欧美777四色影视在线| 久久男女视频| 久久激情五月激情| 久久不射网站| 久久精品成人| 久久久久久久网| 久久久久久午夜| 久久视频免费观看| 久久蜜臀精品av| 久久影视精品| 欧美不卡三区| 欧美日本成人| 欧美日韩国产首页在线观看| 欧美久久综合| 国产精品v亚洲精品v日韩精品 | 一区二区三区|亚洲午夜| 日韩一级精品| 亚洲无毛电影| 欧美一区二区在线看| 久久琪琪电影院| 猛男gaygay欧美视频| 欧美精品免费看| 欧美手机在线| 国产伦精品一区二区三区四区免费 | 中国女人久久久| 亚洲欧美国产日韩中文字幕| 亚洲欧美综合v| 久久久精品tv| 欧美第十八页| 亚洲精品久久嫩草网站秘色 | 亚洲一区二区日本| 欧美一区二区三区的| 久久视频免费观看| 羞羞漫画18久久大片| 亚洲手机成人高清视频| 一区二区黄色| 亚洲国产精品电影在线观看| 亚洲精品乱码久久久久久| 亚洲女同精品视频| 男女激情视频一区| 午夜精品久久久久99热蜜桃导演| 久久这里有精品15一区二区三区| 国产精品ⅴa在线观看h| 亚洲国产一成人久久精品| 久久国产精品久久精品国产| 亚洲精品视频免费| 久久亚洲私人国产精品va| 国产精品一区二区久久国产| 亚洲片在线观看|