日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++服务器websocket支持

發布時間:2023/12/9 c/c++ 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++服务器websocket支持 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

From: https://blog.csdn.net/u010223072/article/details/80637127

介紹

目前公司服務器是c++ 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_cast<const 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_cast<uint8_t>(0x80 | frameType); ?

??? // 填充數據長度
??? if (messageLength <= 0x7d) ?
??? { ?
??????? frameHeader[1] = static_cast<uint8_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大塊就都完成了,即握手、接收解析、發送組裝。
?

總結

以上是生活随笔為你收集整理的c++服务器websocket支持的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。