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

封包和拆包


對于基于TCP開發(fā)的通訊程序,有個很重要的問題需要解決,就是封包和拆包.


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

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

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

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

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

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

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

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

#pragma pack(push,1) //開始定義數(shù)據(jù)包, 采用字節(jié)對齊方式
/*----------------------包頭---------------------*/
typedef struct tagPACKAGEHEAD
{
 BYTE Version;
 WORD Command;
 WORD nDataLen;//包體的長度
}PACKAGE_HEAD;
#pragma pack(pop) //結(jié)束定義數(shù)據(jù)包, 恢復原來對齊方式

然后看存放數(shù)據(jù)和"取"數(shù)據(jù)函數(shù).

/*****************************************************************************
Description:添加數(shù)據(jù)到緩存
Input:pBuff[in]-待添加的數(shù)據(jù);nLen[in]-待添加數(shù)據(jù)長度
Return: 如果當前緩沖區(qū)沒有足夠的空間存放pBuff則返回FALSE;否則返回TRUE。
******************************************************************************/
BOOL CDataBufferPool::AddBuff( char *pBuff, int nLen )
{
 m_cs.Lock();///臨界區(qū)鎖

 if ( nLen < 0 )
 {
  m_cs.Unlock();
  return FALSE;
 }

 if ( nLen <= GetFreeSize() )///判斷剩余空間是否足夠存放nLen長的數(shù)據(jù)
 {
  memcpy(m_pBuff + m_nOffset, pBuff, nLen);
  m_nOffset += nLen;
 }
 else///若不夠則擴充原有的空間
 { 
  char *p = m_pBuff;
  m_nSize += nLen*2;//每次增長2*nLen
  m_pBuff = new char[m_nSize];
  memcpy(m_pBuff,p,m_nOffset);
  delete []p;
  memcpy(m_pBuff + m_nOffset, pBuff, nLen);
  m_nOffset += nLen;
  m_cs.Unlock();
  return FALSE;
 }
 m_cs.Unlock();
 return TRUE;
}

 

/*****************************************************************************
Description:獲取一個完整的包
Input:Buf[out]-獲取到的數(shù)據(jù);nLen[out]-獲取到的數(shù)據(jù)長度
Return: 1、當前緩沖區(qū)不夠一個包頭的數(shù)據(jù) 2、當前緩沖區(qū)不夠一個包體的數(shù)據(jù)
******************************************************************************/

int  CDataBufferPool::GetFullPacket( char *Buf, int& nLen )
{
 m_cs.Lock();

 if ( m_nOffset < m_PacketHeadLen )//當前緩沖區(qū)不夠一個包頭的數(shù)據(jù)
 {
  m_cs.Unlock();
  return 1;
 }
 PACKAGE_HEAD *p = (PACKAGE_HEAD *)m_pBuff;
 if( (m_nOffset-m_PacketHeadLen) < (int)p->nDataLen )//當前緩沖區(qū)不夠一個包體的數(shù)據(jù)
 {
  m_cs.Unlock();
  return 2;
 }
 //判斷包的合法性
/* int IsIntegrallity = ValidatePackIntegrality(p);
 if( IsIntegrallity != 0 )
 {
  m_cs.Unlock();
  return IsIntegrallity;
 }
*/
 nLen = m_PacketHeadLen+p->nDataLen;
 memcpy( Buf, m_pBuff, nLen );
 m_nOffset -= nLen;
 memcpy( m_pBuff, m_pBuff+nLen, m_nOffset );

 m_cs.Unlock();
 return 0;
}


    前面提到過這種方法的缺點.下面給出一個改進辦法, 即采用環(huán)形緩沖.但是這種改進方法還是不能解決第一個缺點以及第一個數(shù)據(jù)拷貝,只能解決第三個地方的數(shù)據(jù)拷貝(這個地方是拷貝數(shù)據(jù)最多的地方).第2種拆包方式會解決這兩個問題.
 環(huán)形緩沖實現(xiàn)方案是定義兩個指針,分別指向有效數(shù)據(jù)的頭和尾.在存放數(shù)據(jù)和刪除數(shù)據(jù)時只是進行頭尾指針的移動.
 用代碼來說明.注:下面的代碼是采用一個開源的游戲服務(wù)器的代碼,我對此代碼有所修改.
 
int CCircularBufferPool::PutData(TCHAR *pData, int len)
{
 if( len <= 0 )
  return 1;

 EnterCriticalSection(&m_cs);
 while (IsOverFlowCondition(len))///判斷緩沖區(qū)剩余空間是否夠存放len長的數(shù)據(jù)
 {
  BufferResize(len);///若不夠,則擴充緩沖區(qū).
 }

 if (IsIndexOverFlow(len))///判斷"尾"指針的位置.
 {
  int FirstCopyLen = m_iBufSize-m_iTailPos;
  int SecondCopyLen = len - FirstCopyLen;
  CopyMemory(m_pBuffer+m_iTailPos, pData, FirstCopyLen);
  if (SecondCopyLen)
  {
   CopyMemory(m_pBuffer, pData+FirstCopyLen, SecondCopyLen);
   m_iTailPos = SecondCopyLen;
  }
  else
   m_iTailPos = 0;
 }
 else
 {
  CopyMemory(m_pBuffer+m_iTailPos, pData, len);
  m_iTailPos += len;
 }

 LeaveCriticalSection(&m_cs);
 return 0;


}


void CCircularBufferPool::GetData(TCHAR *pData, int len, bool Delete)
{
 if (len < m_iBufSize-m_iHeadPos)
 {
  CopyMemory(pData, m_pBuffer+m_iHeadPos, len);
  if(Delete==true)
   m_iHeadPos += len;
 }
 else
 {
  int fc, sc;
  fc = m_iBufSize-m_iHeadPos;
  sc = len - fc;
  CopyMemory(pData, m_pBuffer+m_iHeadPos, fc);
  if (sc) CopyMemory(pData+fc, m_pBuffer, sc);
  if(Delete==true)
   m_iHeadPos = sc;
  if(m_iHeadPos >= m_iBufSize)
   m_iHeadPos = 0;

 }
}

//
//進行自定義包的解析
//
int CCircularBufferPool::GetFullPacket( TCHAR *Buf, int &nLen )
{
 EnterCriticalSection(&m_cs);
 if( GetValidCount() < m_PacketHeadLen )//當前緩沖區(qū)不夠一個包頭的數(shù)據(jù)
 {
  LeaveCriticalSection(&m_cs);
  return 1;
 }

 GetData(Buf,m_PacketHeadLen,false);
 PACKAGE_HEAD *p = (PACKAGE_HEAD *)Buf;
 if( (GetValidCount()-m_PacketHeadLen) < (int)p->nDataLen )//當前緩沖區(qū)不夠一個包體的數(shù)據(jù)
 {
  LeaveCriticalSection(&m_cs);
  return 2;
 }

 //判斷包的合法性
 int IsIntegrallity = ValidatePackIntegrality(p);
 if( IsIntegrallity != 0 )
 {
  LeaveCriticalSection(&m_cs);
  return IsIntegrallity;
 }
 
 GetData(Buf,m_PacketHeadLen+p->nDataLen,true);
 nLen = m_PacketHeadLen+p->nDataLen;

 LeaveCriticalSection(&m_cs);


 return 0;
}

 2.利用底層的緩沖區(qū)來進行拆包
 由于TCP也維護了一個緩沖區(qū),所以我們完全可以利用TCP的緩沖區(qū)來緩存我們的數(shù)據(jù),這樣一來就不需要為每一個連接分配一個緩沖區(qū)了.另一方面我們知道recv或者wsarecv都有一個參數(shù),用來表示我們要接收多長長度的數(shù)據(jù).利用這兩個條件我們就可以對第一種方法進行優(yōu)化了.
      對于阻塞SOCKET來說,我們可以利用一個循環(huán)來接收包頭長度的數(shù)據(jù),然后解析出代表包體長度的那個變量,再用一個循環(huán)來接收包體長度的數(shù)據(jù).
 相關(guān)代碼如下:
  
 char PackageHead[1024];
 char PackageContext[1024*20];

 int len;
 PACKAGE_HEAD *pPackageHead;
 while( m_bClose == false )
 {
  memset(PackageHead,0,sizeof(PACKAGE_HEAD));
  len = m_TcpSock.ReceiveSize((char*)PackageHead,sizeof(PACKAGE_HEAD));
  if( len == SOCKET_ERROR )
  {
      break;
  }
  if(len == 0)
  {
      break;
  }
  pPackageHead = (PACKAGE_HEAD *)PackageHead;
  memset(PackageContext,0,sizeof(PackageContext));
  if(pPackageHead->nDataLen>0)
  {
   len = m_TcpSock.ReceiveSize((char*)PackageContext,pPackageHead->nDataLen);
  }
        }

 m_TcpSock是一個封裝了SOCKET的類的變量,其中的ReceiveSize用于接收一定長度的數(shù)據(jù),直到接收了一定長度的數(shù)據(jù)或者網(wǎng)絡(luò)出錯才返回.
 
int winSocket::ReceiveSize( char* strData, int iLen )
{
 if( strData == NULL )
  return ERR_BADPARAM;
 char *p = strData;
 int len = iLen;
 int ret = 0;
 int returnlen = 0;
 while( len > 0)
 {
  ret = recv( m_hSocket, p+(iLen-len), iLen-returnlen, 0 );
  if ( ret == SOCKET_ERROR || ret == 0 )
  {
   
   return ret;
  }

  len -= ret;
  returnlen += ret;
 }
 
 return returnlen;
}
 對于非阻塞的SOCKET,比如完成端口,我們可以提交接收包頭長度的數(shù)據(jù)的請求,當GetQueuedCompletionStatus返回時,我們判斷接收的數(shù)據(jù)長度是否等于包頭長度,若等于,則提交接收包體長度的數(shù)據(jù)的請求,若不等于則提交接收剩余數(shù)據(jù)的請求.當接收包體時,采用類似的方法.
 下面給出相關(guān)代碼

enum IOType
{
 IOInitialize,
 IORead,
 IOWrite,
 IOIdle
};

class OVERLAPPEDPLUS
{
public:
 OVERLAPPED   m_ol;
 IOType    m_ioType;
 bool         m_bIsPackageHead;//當前接收的數(shù)據(jù)是否是包頭數(shù)據(jù)。

 int          m_count;
 WSABUF       m_wsaBuffer;
 int          m_RecvPos;
 char         m_Buffer[1024*8];//此緩沖要盡可能大

 OVERLAPPEDPLUS(IOType ioType) {
  ZeroMemory(this, sizeof(OVERLAPPEDPLUS));
  m_ioType = ioType;
 }
};
接收連接后發(fā)出的第一個請求,請求接收包頭大小的數(shù)據(jù).
 OVERLAPPEDPLUS *pOverlappedPlus =  new OVERLAPPEDPLUS;
 pOverlappedPlus->m_wsaBuffer.buf =  pOverlappedPlus->m_Buffer;
 pOverlappedPlus->m_wsaBuffer.len =  PACKAGE_HEAD_LEN;///包頭的長度
 pOverlappedPlus->m_bIsPackageHead = true;
 pOverlappedPlus->m_RecvPos = 0;
 pOverlappedPlus->m_ioType = IORead;


 DWORD RecvBytes;
     DWORD Flags;
 Flags = 0;
 if (WSARecv(clientSocket, &(pOverlappedPlus->m_wsaBuffer), 1, &RecvBytes, &Flags,
  &pOverlappedPlus->m_ol, NULL) == SOCKET_ERROR)
 {
  if (WSAGetLastError() != ERROR_IO_PENDING)
  {
   delete pOverlappedPlus;
  }
  else
  {
   ///相關(guān)的錯誤處理

  }
 }
 else
 {
  ///相關(guān)的錯誤處理

 }


在GetQueuedCompletionStatus所在的函數(shù)中.
 if( pOverlapPlus->m_ioType== IORead)
 { 
  if( pOverlapPlus->m_wsaBuffer.len == dwIoSize )
  {
   if( pOverlapPlus->m_bIsPackageHead == true )///接收到的是包頭。
   {
    PACKAGE_HEAD *pPackageHead = (PACKAGE_HEAD *)(pOverlapPlus->m_Buffer);

    if(pThis->IsLegalityPackageHead(pPackageHead)==false)///判斷是否是合法的包
    {
     closesocket(lpClientContext->m_Socket);
     continue;
    }

    pOverlapPlus->m_bIsPackageHead = false;
    pOverlapPlus->m_wsaBuffer.len = pPackageHead->nDataLen;
    pOverlapPlus->m_RecvPos += dwIoSize;
    pOverlapPlus->m_wsaBuffer.buf = pOverlapPlus->m_Buffer+pOverlapPlus->m_RecvPos;

   }
   else///接收到的是包體
   {

     

   pOverlapPlus->m_RecvPos += dwIoSize;
   ///這時pOverlapPlus->m_Buffer里就存放了一個完整的數(shù)據(jù)包,長度為pOverlapPlus->m_RecvPos
   

   ///繼續(xù)請求 請求下一個數(shù)據(jù)包的包頭
   pOverlapPlus->m_wsaBuffer.buf =  pOverlapPlus->m_Buffer;
   memset(pOverlapPlus->m_Buffer,0,sizeof(pOverlapPlus->m_Buffer));
   pOverlapPlus->m_wsaBuffer.len =  PACKAGE_HEAD_LEN;
   pOverlapPlus->m_bIsPackageHead = true;
   pOverlapPlus->m_RecvPos = 0;
     
   }
  }
  else///接收的數(shù)據(jù)還不完整
  {
   pOverlapPlus->m_wsaBuffer.len -= dwIoSize;
   pOverlapPlus->m_RecvPos += dwIoSize;
   pOverlapPlus->m_wsaBuffer.buf = pOverlapPlus->m_Buffer+pOverlapPlus->m_RecvPos;
  }
  pOverlapPlus->m_ioType = IORead;
  state = WSARecv(lpClientContext->m_Socket, &(pOverlapPlus->m_wsaBuffer), 1, &RecvBytes, &Flags,
    &pOverlapPlus->m_ol, NULL);
  if ( state == SOCKET_ERROR)
  {
   if(WSAGetLastError() != ERROR_IO_PENDING)
   {
      
       //關(guān)閉套接字 釋放相應(yīng)資源
     continue;
   }
  }
   
 }

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

 

posted on 2008-04-16 09:00 RedLight 閱讀(1441) 評論(0)  編輯 收藏 引用 所屬分類: 網(wǎng)絡(luò)服務(wù)器開發(fā)

<2008年4月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

導航

統(tǒng)計

公告


Name: Galen
QQ: 88104725

常用鏈接

留言簿(3)

隨筆分類

隨筆檔案

相冊

My Friend

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            香蕉久久夜色精品国产| 国产又爽又黄的激情精品视频 | 国内伊人久久久久久网站视频| 亚洲手机成人高清视频| 亚洲区一区二| 国产欧美日韩在线| 国产精品久久久久久久久婷婷| 一本一本a久久| 一本色道久久综合亚洲精品不卡| 欧美影院久久久| 久久九九99视频| 久久国产精品99国产精| 亚洲国产福利在线| 欧美激情一区二区三区在线视频观看| 一本色道久久综合| 狂野欧美激情性xxxx欧美| 午夜久久美女| 欧美成人免费在线| 午夜亚洲视频| 欧美淫片网站| 最新高清无码专区| 久久狠狠婷婷| 欧美国产日本| 久久久久国内| 欧美一区二区三区在| 狂野欧美一区| 蜜臀av国产精品久久久久| 午夜精品国产更新| 免费人成网站在线观看欧美高清 | 国产精品av一区二区| 国产精品女主播一区二区三区| 免费成人你懂的| 国产精品成人在线观看| 免费看亚洲片| 亚洲无限av看| 玖玖精品视频| 韩国av一区二区三区四区| 亚洲视频在线观看| 玖玖视频精品| 羞羞漫画18久久大片| 欧美四级伦理在线| 99日韩精品| 欧美刺激午夜性久久久久久久| 欧美在线亚洲一区| 99精品福利视频| 欧美巨乳在线| 欧美日韩一区二区三区| 悠悠资源网亚洲青| 久久久久久一区| 亚洲欧美亚洲| 国产精品午夜在线| 亚洲伊人伊色伊影伊综合网| 亚洲黄色片网站| 欧美大片在线观看一区| 亚洲国产高清视频| 美日韩精品视频免费看| 欧美在线三区| 狠狠色狠狠色综合| 久久人人97超碰精品888| 亚洲第一精品夜夜躁人人躁| 欧美一区二区三区视频在线| 国产精品青草综合久久久久99| 国产视频在线观看一区二区| 国产一区视频在线看| 欧美专区18| 欧美中文字幕在线播放| 国精品一区二区| 国产专区综合网| 性欧美1819性猛交| 欧美一区二区三区视频免费播放| 免费成人av在线看| 亚洲另类春色国产| 亚洲精品视频啊美女在线直播| 亚洲一区亚洲二区| 国产日韩精品视频一区二区三区| 亚洲国产天堂久久综合| 欧美 日韩 国产在线| 日韩天堂在线观看| 欧美日韩一区综合| 尤妮丝一区二区裸体视频| 久久伊人一区二区| 免费日韩成人| 亚洲资源av| 久久国产婷婷国产香蕉| 欧美日韩精品福利| 午夜国产精品视频免费体验区| 你懂的视频欧美| 欧美刺激午夜性久久久久久久| 国产一区二区高清不卡| 免费在线观看成人av| 欧美激情精品久久久六区热门 | 亚洲一区二区三区四区视频| 欧美天堂亚洲电影院在线播放 | 亚洲激情av| 在线观看视频免费一区二区三区| 亚洲夜晚福利在线观看| 亚洲永久字幕| 在线日本高清免费不卡| 亚洲人成网站777色婷婷| 国产精品色午夜在线观看| 久久亚洲综合色一区二区三区| 亚洲高清资源综合久久精品| 亚洲激情专区| 国产日韩专区在线| 亚洲国产婷婷香蕉久久久久久99 | 一本色道久久综合亚洲精品高清| 久久久久久夜| 一区二区免费看| 亚欧成人精品| 亚洲免费观看在线观看| 欧美亚洲综合网| 亚洲午夜精品17c| 久久色在线观看| 欧美一区二区日韩一区二区| 欧美黄色一级视频| 蜜桃av一区二区三区| 国产精品天美传媒入口| 亚洲日本一区二区| 欧美va天堂| 久热精品视频在线免费观看| 国产精品黄视频| 亚洲精品一区二区三区婷婷月| 欧美精品成人一区二区在线观看| 伊人久久婷婷色综合98网| 久久尤物视频| 国产精品欧美在线| 一本大道久久精品懂色aⅴ| 亚洲激情亚洲| 蜜臀91精品一区二区三区| 亚洲精品日韩在线| 久久国产直播| 久久国产精品久久久久久电车| 亚洲午夜久久久久久尤物| 亚洲激情第一区| 另类酷文…触手系列精品集v1小说| 亚洲国产合集| 久久精品国产亚洲高清剧情介绍| 好看的亚洲午夜视频在线| 亚洲免费观看| 国产日韩欧美在线视频观看| 久久久久国产精品www| 先锋亚洲精品| 亚洲欧美国产高清| 欧美精品亚洲精品| 国产欧美日韩综合精品二区| 日韩视频在线你懂得| 国产精品99一区| 久久久午夜电影| 国产精品久久久久久亚洲调教| 午夜精品免费在线| 国产精品成人观看视频国产奇米| 亚洲在线一区| 欧美性色aⅴ视频一区日韩精品| 久久男人av资源网站| 欧美福利在线| 亚洲精品国精品久久99热| 亚洲黄色成人| 亚洲图片欧美午夜| 久久精品国产久精国产爱| 国产亚洲欧美日韩精品| 午夜一区二区三视频在线观看| 亚洲人成亚洲人成在线观看图片 | 亚洲欧洲精品一区| 一本综合精品| 国产精品丝袜白浆摸在线| 欧美一级理论性理论a| 欧美国产一区二区在线观看| 欧美日韩在线另类| 亚洲欧美成人精品| 久久男人资源视频| 日韩视频在线你懂得| 国产精品视频免费在线观看| 91久久午夜| 亚洲网在线观看| 黄色亚洲在线| 欧美日韩国产三区| 亚洲欧美日韩国产中文 | 国产亚洲日本欧美韩国| 久久aⅴ国产欧美74aaa| 亚洲国产精品久久| 欧美一级淫片播放口| 在线观看视频日韩| 国产精品美腿一区在线看 | 免费观看成人网| 夜夜夜精品看看| 欧美va亚洲va国产综合| 亚洲视频网在线直播| 精品9999| 国产麻豆精品theporn| av不卡在线观看| 久久永久免费| 亚洲女人天堂av| 最新日韩av| 国产亚洲精品久久久久婷婷瑜伽| 欧美性生交xxxxx久久久| 久久综合九色综合久99| 欧美视频三区在线播放| 久久久久久久久伊人| 亚洲天堂网在线观看| 亚洲精品美女91|