自己搭建网站,为网站开发,淘宝小程序开发文档,网站代码优化方案From: https://blog.csdn.net/u010223072/article/details/80637127
介绍
目前公司服务器是c tcp的网络架构#xff0c;现在想用这套做h5游戏#xff0c;所以要扩展支持websocket通信。
那么什么是websocket#xff1f;它和tcp有什么区别#xff1f;这些随便一搜一大把 tcp的网络架构现在想用这套做h5游戏所以要扩展支持websocket通信。
那么什么是websocket它和tcp有什么区别这些随便一搜一大把这里就不再科普达。通俗简单点讲websocket就是山寨版的tcp它底层实现就是tcp唯一的区别就是网络传输时websocket协议前面多了个标志它的包头信息。去掉前面这部分包头剩下的就和普通tcp一样了。
那么讲到这里在现有tcp上怎么扩展支持websocket其实就很简单呢既然它和tcp协议上就只是多了个包头部分那么我们的任务其实主要就是怎么解析这个包头信息了。
最后还有一个需要注意的细节是websocket协议前后端建立连接前需要一次握手协议触发时机是client发起connet连接请求时会向server发送这条握手的协议server收到后要回复client这样就建立了连接了。
好闲话少说下面直接上实现代码… 实现
1.握手。 client第一次connet连接会发起握手协议server在recv接收处解析判断如果是websocket的握手协议那么同样组装好特定格式包头回复给client建立连接。 判断是不是websocket协议
bool isWSHandShake(std::string request) { size_t i request.find(GET); if(i std::string::npos){ return false; } return true; } 如果是解析握手协议重新组装准备send回复给client
bool wsHandshake(std::string request, std::string response) { //得到客户端请求信息的key std::string tempKey request; size_t i tempKey.find(Sec-WebSocket-Key); if(i std::string::npos){ return false; } tempKey tempKey.substr(i 19, 24); //拼接协议返回给客户端 response HTTP/1.1 101 Switching Protocols\r\n; response Connection: upgrade\r\n; response Sec-WebSocket-Accept: ; std::string realKey tempKey; realKey 258EAFA5-E914-47DA-95CA-C5AB0DC85B11; SHA1 sha; unsigned int message_digest[5]; sha.Reset(); sha realKey.c_str(); sha.Result(message_digest); for (int i 0; i 5; i) { message_digest[i] htonl(message_digest[i]); } realKey base64_encode(reinterpret_castconst unsigned char*(message_digest), 20); realKey \r\n; response realKey.c_str(); response Upgrade: websocket\r\n\r\n; return true; } 2.接收client协议解析 首先解析包头信息
bool wsReadHeader(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 WS_FrameType::WS_CONTINUATION_FRAME) { //连续帧 return false; } else if (header-opcode WS_FrameType::WS_TEXT_FRAME) { //文本帧 } else if (header-opcode WS_FrameType::WS_BINARY_FRAME) { //二进制帧 } else if (header-opcode WS_FrameType::WS_CLOSING_FRAME) { //连接关闭消息 return true; } else if (header-opcode WS_FrameType::WS_PING_FRAME) { // ping return false; } else if (header-opcode WS_FrameType::WS_PONG_FRAME) { // 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; } 然后根据包头解析出真是数据
bool wsDecodeFrame(const WebSocketStreamHeader header, unsigned char cbSrcData[], unsigned short wSrcLen, unsigned char 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 WS_FrameType::WS_TEXT_FRAME) cbTagData[header.payload_size] \0; return true; } 3.组装server发给client协议
bool wsEncodeFrame(std::string inMessage, std::string outFrame, enum WS_FrameType frameType) { const uint32_t messageLength inMessage.size(); if (messageLength 32767) { // 暂不支持这么长的数据 return false; } uint8_t payloadFieldExtraBytes (messageLength 0x7d) ? 0 : 2; // header: 2字节, mask位设置为0(不加密), 则后面的masking key无须填写, 省略4字节 uint8_t frameHeaderSize 2 payloadFieldExtraBytes; uint8_t *frameHeader new uint8_t[frameHeaderSize]; memset(frameHeader, 0, frameHeaderSize); // fin位为1, 扩展位为0, 操作位为frameType frameHeader[0] static_castuint8_t(0x80 | frameType); // 填充数据长度 if (messageLength 0x7d) { frameHeader[1] static_castuint8_t(messageLength); } else { frameHeader[1] 0x7e; uint16_t len htons(messageLength); memcpy(frameHeader[2], len, payloadFieldExtraBytes); } // 填充数据 uint32_t frameSize frameHeaderSize messageLength; char *frame new char[frameSize 1]; memcpy(frame, frameHeader, frameHeaderSize); memcpy(frame frameHeaderSize, inMessage.c_str(), messageLength); outFrame std::string(frame, frameSize); delete[] frame; delete[] frameHeader; return true; } 至此tcp上扩展websocket所需要处理的3大块就都完成了即握手、接收解析、发送组装。