1. 程式人生 > >VS C++ 服務端解析WebSocket資料包

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