VS C++ 服務端解析WebSocket資料包
阿新 • • 發佈:2019-01-02
WebSocket傳送資料時,會將您的傳送資料進行一定格式的封包處理,具體協議格式網上很多文章介紹,大家直接問度娘。這裡我直接上VC++ 的處理程式碼。
先定義資料包格式頭結構:
//Websocket資料包資料頭資訊 struct WebSocketStreamHeader { unsigned int header_size; //資料包頭大小 int mask_offset; //掩碼偏移 unsigned int payload_size; //資料大小 bool fin; //幀標記 bool masked; //掩碼 unsigned char opcode; //操作碼 unsigned char res[3]; };
資料包頭操作型別定義
// 資料包操作型別
enum WebSocketOpCode {
ContinuationFrame = 0x0, //連續幀
TextFrame = 0x1, //文字幀
BinaryFrame = 0x2, //二進位制幀
ConnectionClose = 0x8, //連線關閉
Ping = 0x9,
Pong = 0xA
};
根據資料包獲取資料包頭資訊:
bool ReadHeader(const unsigned char* cData, WebSocketStreamHeader* header) { if (cData == NULL)return false; const unsigned char *buf = cData; header->fin = buf[0] & 0x80; header->masked = buf[1] & 0x80; unsigned char stream_size = buf[1] & 0x7F; header->opcode = buf[0] & 0x0F; if (header->opcode == WebSocketOpCode::ContinuationFrame) { //連續幀 return false; } else if (header->opcode == WebSocketOpCode::TextFrame) { //文字幀 } else if (header->opcode == WebSocketOpCode::BinaryFrame) { //二進位制幀 } else if (header->opcode == WebSocketOpCode::ConnectionClose) { //連線關閉訊息 return false; } else if (header->opcode == WebSocketOpCode::Ping) { // ping return false; } else if (header->opcode == WebSocketOpCode::Pong) { // pong return false; } else { //非法幀 return false; } if (stream_size <= 125) { // small stream header->header_size =6; header->payload_size = stream_size; header->mask_offset = 2; } else if (stream_size == 126) { // medium stream header->header_size = 8; unsigned short s = 0; memcpy(&s, (const char*)&buf[2], 2); header->payload_size = ntohs(s); header->mask_offset = 4; } else if (stream_size == 127) { unsigned long long l = 0; memcpy(&l, (const char*)&buf[2], 8); header->payload_size = l; header->mask_offset = 10; } else { //Couldnt decode stream size 非法大小資料包 return false; } if (header->payload_size > MAX_WEBSOCKET_BUFFER) { return false; } return true; }
根據分析的資料包頭,解碼資料包資訊:
// 解碼WebSocket資料 bool DecodeRawData(const WebSocketStreamHeader& header, BYTE cbSrcData[], WORD wSrcLen, BYTE cbTagData[]) { const unsigned char *final_buf = cbSrcData; if (wSrcLen < header.header_size + 1) { return false; } char masks[4]; memcpy(masks, final_buf + header.mask_offset, 4); memcpy(cbTagData, final_buf + header.mask_offset + 4, header.payload_size); for (INT_PTR i = 0; i < header.payload_size; ++i){ cbTagData[i] = (cbTagData[i] ^ masks[i % 4]); } //如果是文字包,在資料最後加一個結束字元“\0” if (header.opcode==WebSocketOpCode::TextFrame) cbTagData[header.payload_size] = '\0'; return true; }