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