VS C++ 服務端解析WebSocket數據包

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


發佈了35 篇原創文章 · 獲贊 21 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章