eATM

vc++实现webSocket服务器

webSocket协议参考:https://www.cnblogs.com/lizhenghn/p/5155933.html

vc++/mfc实现 webSocket Server核心代码:

//处理握手过程
pStream->Append(buf,len);


//非法请求
if (pStream->GetLength()>=3
  && memcmp(pStream->GetCharBuffer(),"GET",3)!=0)
{
  CSRIOCPS::CloseClient(pClient);
  return;
}

int nEndChar=pStream->Find("\r\n\r\n");
if (nEndChar==-1)
{
  //设置Request Header最大字节数64KB
  if (pStream->GetLength()>=1024*64)
  {
    CSRIOCPS::CloseClient(pClient);
  }
  return;
}

CString Connection=pStream->GetHttpHeader("Connection");
CString Upgrade=pStream->GetHttpHeader("Upgrade");
CString SecWebSocketKey=pStream->GetHttpHeader("Sec-WebSocket-Key");

//判断是否webSocket握手协议
if (Upgrade.CompareNoCase("websocket")!=0
  || SecWebSocketKey.IsEmpty()
  || Connection.IsEmpty())
{
  CSRIOCPS::CloseClient(pClient);
  return;
}
    
//此GUID在webSocket协议中固定!
#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

//拼接数据
CString AcceptKey(SecWebSocketKey);
AcceptKey+=WEBSOCKET_GUID;

//对数据先SHA1,再Base64
BYTE sha1Byte[20]={0};
CEncrypt::SHA1(AcceptKey,sha1Byte);
AcceptKey=CEncrypt::Base64Encode(sha1Byte,20);

//组合Response Header
CString bodyStr;
bodyStr="HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ";
bodyStr+=AcceptKey;
bodyStr+="\r\n\r\n";

CSRIOCPS::SendData(pClient,bodyStr,bodyStr.GetLength());

//客户端在握手前不会发送数据,握手后删除所有数据-无需判断包长
pStream->DeleteAll();

//设置当前连接已握手
pWSocket->bHS=TRUE;
//自定义webSocket包头结构体
struct _PER_WS_HEAD
{
  BYTE FIN;
  BYTE RSV1;
  BYTE RSV2;
  BYTE RSV3;
  BYTE OPCODE;
  BYTE MASK;
  UINT PayloadLen;
  BYTE MaskKey[4];
  
  _PER_WS_HEAD()
  {
    Empty();
  }
  
  void Empty()
  {
    FIN=0;
    RSV3=0;
    RSV2=0;
    RSV1=0;
    OPCODE=0;
    MASK=0;
    PayloadLen=0;
    RtlZeroMemory(&MaskKey,sizeof(MaskKey));
  }
};
//解析webSocket包头
BOOL CSRWebSocket::DecWSocketHead(char* lpBuffer,int nLength,_PER_WS_HEAD* pHead,int &nHeadLength,BOOL &bError)
{
  if (nLength<2) return FALSE;
  
  BYTE *lpBuf=(BYTE*)lpBuffer;
  
  int nPos=0;
  
  //解析头
  BYTE bit1=lpBuf[nPos++];
  BYTE bit2=lpBuf[nPos++];
  
  pHead->FIN=bit1>>7;
  BYTE OPCODE=bit1 & 0xF;
  if (OPCODE!=0) pHead->OPCODE=OPCODE;
  
  pHead->MASK=bit2>>7;
  pHead->PayloadLen=bit2 & 0x7F;
  
  if (pHead->PayloadLen==126)
  {
    if (nLength<4) return FALSE;
    WORD wlen=(*((WORD*)(&lpBuf[nPos])));
    pHead->PayloadLen=htons(wlen);
    nPos+=2;
  }else if (pHead->PayloadLen==127)
  {
    if (nLength<10) return FALSE;
    
    DWORD dwLen=(*((DWORD*)(&lpBuf[nPos])));
    if (dwLen)
    {
      //如果这位有数据则是大于2G的数据
      bError=TRUE;
      return FALSE;
    }
    nPos+=4;
    dwLen=(*((DWORD*)(&lpBuf[nPos])));
    pHead->PayloadLen=htonl(dwLen);
    nPos+=4;
  }
  
  if (pHead->MASK)
  {
    if (nLength-nPos<4)
    {
      return FALSE;
    }
    memcpy(&pHead->MaskKey[0],&lpBuf[nPos],4);
    nPos+=4;
  }
  
  //包头字节数
  nHeadLength=nPos;
  
  return TRUE;
}
//对设置了MASK的实体数据进行异或解码
void CSRWebSocket::DecWSocketPayload(char* lpBuffer,int nLength,BYTE *MaskKey)
{
  char *lpOldBuf=lpBuffer;

  char *lpDWORD_END=NULL;
  if(nLength>=4) lpDWORD_END=lpBuffer+nLength-(nLength%4);
  
  char *lpEnd=lpBuffer+nLength;
  
  //先按4字节异或运算
  if (lpDWORD_END)
  {
    int nKeyAt=0;
    do 
    {
      *((DWORD*)lpBuffer)=*((DWORD*)lpBuffer)^*((DWORD*)MaskKey);
      lpBuffer+=4;
    } while (lpBuffer<lpDWORD_END);
  }
  
  //对剩余的按1字节异或
  int nKeyAt=0;
  while (lpBuffer<lpEnd)
  {
    *lpBuffer^=MaskKey[nKeyAt];
    if(++nKeyAt==4) nKeyAt=0;
    lpBuffer++;
  }
}
//发送数据代码
BOOL CSRWebSocket::SendWSocket(WSHANDLE hWebSocket,BYTE OPCODE,BYTE *buf,int len)
{
    CSRStream stream;
    
    //组包
    BYTE btWS[2]={0};
    btWS[0]=0x80 | OPCODE;

    if (len<=125)
    {
        btWS[1]=len;
        stream.Append(&btWS,2);
    }else if (len<=65535)
    {
        btWS[1]=126;
        stream.Append(&btWS,2);
        stream.Append(htons(len));
    }else{
        btWS[1]=127;
        stream.Append(&btWS,2);
        stream.Append((DWORD)0);
        stream.Append(htonl(len));
    }
    
    stream.Append(buf,len);
    
    return CSRIOCPS::SendData(hWebSocket,stream.GetCharBuffer(),stream.GetLength())!=0;
}

 

typedef struct _PRE_WSOCKET_DATA
{
  WSHANDLE hWebSocket;
  int len;
  const char *data;
  WSDT type;
}WS_DATA;

struct _PER_WS_HEAD
{
  BYTE FIN;
  BYTE RSV1;
  BYTE RSV2;
  BYTE RSV3;
  BYTE OPCODE;
  BYTE MASK;
  UINT PayloadLen;
  BYTE MaskKey[4];
  
  _PER_WS_HEAD()
  {
    Empty();
  }
  
  void Empty()
  {
    FIN=0;
    RSV3=0;
    RSV2=0;
    RSV1=0;
    OPCODE=0;
    MASK=0;
    PayloadLen=0;
    RtlZeroMemory(&MaskKey,sizeof(MaskKey));
  }
};

struct _PER_WEBSOCKET
{
  CSRStream	headStream;		//数据流
  
  BOOL		bHS;		//是否已经握手
  BOOL		bSendComplete;	//发送后关闭
  
  _PER_WS_HEAD curHead;
  
  //已解包的数据长度
  int  nDecDataLength;
    
  //当前包读取的数据长度
  int  nCurRecvDataLength;

  //协议头ok
  BOOL		bDecHead;

  _PER_WEBSOCKET()
  {
    Empty();
  }
  
  void	Empty()
  {
    bHS=FALSE;
    bSendComplete=FALSE;
    curHead.Empty();
    nDecDataLength=0;
    bDecHead=FALSE;
    nCurRecvDataLength=0;
  }
};


void CSRWebSocket::OnConnect(PPER_CLIENT pClient)
{
  pClient->m_lPrarm=(LPVOID)new _PER_WEBSOCKET;
  CSRIOCPS::OnConnect(pClient);
}
void CSRWebSocket::OnDisconnect(PPER_CLIENT pClient)
{
  if(pClient->m_lPrarm) delete (_PER_WEBSOCKET*)(pClient->m_lPrarm);
  CSRIOCPS::OnDisconnect(pClient);
}

void CSRWebSocket::OnRecv(PPER_CLIENT pClient,char *buf,int len)
{
  _PER_WEBSOCKET	*pWSocket=(_PER_WEBSOCKET*)pClient->m_lPrarm;
  if(!pWSocket)
  {
    CloseClient(pClient);
    return;
  }
  
  CSRStream *pStream=&pWSocket->headStream;
  
  //判断是否已握手
  if (pWSocket->bHS)
  {
    _PER_WS_HEAD *pHead=&pWSocket->curHead;
    
    pStream->Append(buf,len);
    
    if (!pWSocket->bDecHead)
    {
      BOOL bError=FALSE;
      int  nHeaderLength=0;
      if(!DecWSocketHead((char*)pStream->GetCharBuffer()+pWSocket->nDecDataLength,
        pStream->GetLength()-pWSocket->nDecDataLength,pHead,nHeaderLength,bError)
        )
      {
        if(bError) CSRIOCPS::CloseClient(pClient);
        return;
      }

      //删除head
      if (nHeaderLength && pStream->GetLength()>=(pWSocket->nDecDataLength+nHeaderLength))
      {
        pStream->Delete(pWSocket->nDecDataLength,nHeaderLength);
      }
      
      //设置已解包头
      pWSocket->bDecHead=TRUE;
    }
    
    UINT nTmpLength=pStream->GetLength()-pWSocket->nDecDataLength;
    
    //数据包完成!
    if (nTmpLength>=pHead->PayloadLen)
    {
      
      //数据需要异或解码
      if (pHead->PayloadLen && pHead->MASK)
      {
        //解码数据
        DecWSocketPayload((char*)pStream->GetCharBuffer()+pWSocket->nDecDataLength,pHead->PayloadLen,pHead->MaskKey);
        pWSocket->nDecDataLength+=pHead->PayloadLen;
      }
      
      //所有分包已完成!
      if (pHead->FIN)
      {
        //数据包
        if ((pHead->OPCODE==0x1 || pHead->OPCODE==0x2)
          && pWSocket->nDecDataLength)
        {
          _PRE_WSOCKET_DATA wsData={0};
          wsData.hWebSocket=pClient->m_clientId;
          wsData.data=pStream->GetCharBuffer();
          wsData.len=pWSocket->nDecDataLength;
          wsData.type=(WSDT)pHead->OPCODE;
          
          BOOL bError=FALSE;
          
          //备份当前数据最后1个字符 并置0,方便子类读取字符串
          BOOL bBakData=FALSE;
          BYTE bitBak=0;
          if (pStream->GetLength()>wsData.len)
          {
            bBakData=TRUE;
            bitBak=*((char*)(pStream->GetCharBuffer()+wsData.len));
            *((char*)(pStream->GetCharBuffer()+wsData.len))=0;
          }

          OnWSocket(&wsData,bError);
          if (bError)
          {
            CSRIOCPS::CloseClient(pClient);
            return;
          }
          if (bBakData) *((char*)(pStream->GetCharBuffer()+wsData.len))=bitBak;
        }
        
        if (pWSocket->nDecDataLength)
        {
          pStream->Delete(0,pWSocket->nDecDataLength);
          pWSocket->nDecDataLength=0;
        }
        
        if (pHead->OPCODE==8)
        {
          CSRIOCPS::CloseClient(pClient);
          return;
        }

        pHead->Empty();
      }
      
      //当前包已处理完,重置解包头
      pWSocket->bDecHead=FALSE;
      
      //如果还有数据,继续处理
      if (pStream->GetLength())
      {
        CSRWebSocket::OnRecv(pClient,NULL,0);
      }
    }
  }else{

    //处理握手过程
    pStream->Append(buf,len);
    

    //非法请求
    if (pStream->GetLength()>=3
      && memcmp(pStream->GetCharBuffer(),"GET",3)!=0)
    {
      CSRIOCPS::CloseClient(pClient);
      return;
    }

    int nEndChar=pStream->Find("\r\n\r\n");
    if (nEndChar==-1)
    {
      //设置Request Header最大字节数64KB
      if (pStream->GetLength()>=1024*64)
      {
        CSRIOCPS::CloseClient(pClient);
      }
      return;
    }
    
    CString Connection=pStream->GetHttpHeader("Connection");
    CString Upgrade=pStream->GetHttpHeader("Upgrade");
    CString SecWebSocketKey=pStream->GetHttpHeader("Sec-WebSocket-Key");
    
    //判断是否webSocket握手协议
    if (Upgrade.CompareNoCase("websocket")!=0
      || SecWebSocketKey.IsEmpty()
      || Connection.IsEmpty())
    {
      CSRIOCPS::CloseClient(pClient);
      return;
    }
        
    //此GUID在webSocket协议中固定!
    #define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
    
    //拼接数据
    CString AcceptKey(SecWebSocketKey);
    AcceptKey+=WEBSOCKET_GUID;
    
    //对数据先SHA1,再Base64
    BYTE sha1Byte[20]={0};
    CEncrypt::SHA1(AcceptKey,sha1Byte);
    AcceptKey=CEncrypt::Base64Encode(sha1Byte,20);
    
    //组合Response Header
    CString bodyStr;
    bodyStr="HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ";
    bodyStr+=AcceptKey;
    bodyStr+="\r\n\r\n";
    
    CSRIOCPS::SendData(pClient,bodyStr,bodyStr.GetLength());
    
    //客户端在握手前不会发送数据,握手后删除所有数据-无需判断包长
    pStream->DeleteAll();
    
    //设置当前连接已握手
    pWSocket->bHS=TRUE;
  }

}

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注