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; } }
14