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大块就都完成了,即握手、接收解析、发送组装。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402779.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu10.04制作官方源镜像以及搭建本地源

不能上网、网速慢、共享等等需求&#xff0c;使我们不能或者不想使Ubuntu10.04在线安装软件包&#xff0c;而是需要一个本地的更新源。通过apt-mirror工具&#xff0c;我们可以轻松制作官方源的本地镜像&#xff0c;通过本地镜像&#xff0c;我们可以本地安装更新软件. 1. 安装…

学习《css世界》笔记之使用vertical-align数值实现文字和小图标对齐

效果图 HTML <p>请选择<i class"icon-arrow"></i></p> <p>请选择<i class"icon-arrow valing-1"></i></p> <p>请选择<i class"icon-arrow valing-2"></i></p>CSS .i…

dll 和 lib--初级

今天碰到一个奇怪的问题&#xff0c;一个第三方的库&#xff0c;提供了A.dll和A.lib,编译的时候可以通过&#xff0c;运行的时候一直报错&#xff0c;说找不到A.dll。 我就在main函数那里设了断点&#xff0c;发现没有进main 函数的时候就已经报错了&#xff0c;应该是在入口函…

[Mac] php安装protobuf扩展

环境: mac os x 10.10.3 [zcmGatewayWorker 19]$php -v PHP 7.2.5 (cli) (built: May 1 2018 09:50:45) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologieswith Xdebug v2.6.0, Copyright (c) 2002-2018, by De…

MS SQL 能否修改实例名称

前几天研究了了一下修改数据库名称的方式后&#xff0c;今天突然冒出一个问题&#xff0c;MS SQL的命名实例是否也可以修改呢&#xff1f;例如下图&#xff0c;我在本机上安装了一个命名实例GSP&#xff0c;如果我想将其改为GSPS&#xff0c;能行吗&#xff1f; 如果可以&#…

MYSQL数据库时间字段INT,TIMESTAMP,DATETIME性能效率比较

from: http://www.piaoyi.org/database/MYSQL-INT-TIMESTAMP-DATETIME.html Author&#xff1a;飘易 Source&#xff1a;飘易 Categories&#xff1a;数据库 PostTime&#xff1a;2016-10-28 13:12:22 正 文&#xff1a; 在数据库设计的时候&#xff0c;我们经常会需要设计时…

学习《css世界》笔记之使用overflow做文字溢出点点点效果

效果图 HTML <p class"p1">qwertyuiopasdfghjklzxcvbnm</p><div class"d1"><p> 冯塘村过去经济较为落后。几年前&#xff0c;镇里以400多年的冯塘古村为基础&#xff0c;引来社会资金投资休闲农庄和共享民宿&#xff0c;把这里建…

关于 部署方面研究 Visual Studio 2013

InstallShield2013LimitedEdition 下载地址 http://download.csdn.net/download/yuanyuan_186/7681385 转载于:https://www.cnblogs.com/tianheBologs/p/5996361.html

Portal-Basic Java Web 应用开发框架:应用篇(十四) —— 异步 Action

Portal-Basic Java Web应用开发框架&#xff08;简称 Portal-Basic&#xff09;是一套功能完备的高性能Full-Stack Web应用开发框架&#xff0c;内置稳定高效的MVC基础架构和DAO框架&#xff08;已内置Hibernate、MyBatis和JDBC支持&#xff09;&#xff0c;集成 Action拦截、F…

类似No module named 'bs4'等错误的解决方法

from: https://www.cnblogs.com/xisheng/p/7856334.html 最近开始接触爬虫&#xff0c;写了如下源代码&#xff1a; from bs4 import BeautifulSoup import requests urlhttps://www.tripadvisor.cn/Attractions-g60763-Activities-New_York_City_New_York.html wb_datereque…

C. Vanya and Scales

C. Vanya and Scalestime limit per test1 secondmemory limit per test256 megabytesinputstandard inputoutputstandard outputVanya has a scales for weighing loads and weights of masses w0, w1, w2, ..., w100 grams where w is some integer not less than 2(exac…

js_组合继承(最常用的继承方式)

<script type"text/javascript">//组合继承: 将原型链和借用构造函数的技术组合在一起//使用原型链实现对原型方法的继承//使用构造函数实现对实例属性的继承//js中最常用的继承方式//super:超类function SuperType(name) {//超类属性//使用构造函数实现对实例…

Hello World(本博客启程篇)

Hello World 作为本博客第一篇日志&#xff0c;作为程序员&#xff0c;无论走到哪里&#xff0c;做什么事&#xff0c;必须先输出这句话。 一个想法  从今天3月份到现在一直在学技术&#xff0c;过程中坑的解决、知识的总结以及想法等都写到了“有道云笔记”。 写有道云笔记的…

php7.2 event扩展php_sockets_le_socket错误解决

环境: [rootlocalhost php.d]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) [rootlocalhost php.d]# php -v PHP 7.2.10 (cli) (built: Sep 15 2018 07:10:58) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-201…

NYOJ_37_回文字符串

首先&#xff0c;我们把字符串反转&#xff0c;然后用反串和原串求最大公共子序列&#xff0c;再用字符串长度减去最大公共子序列的长度就是答案&#xff0c;我们还可以用滚动数组优化内存 状态转移方程&#xff1a; (i长度的a串和j长度的b串的最长公共子序列长度&#xff09; …

js中的Object.create(null) 和 {} 的区别

console.log(Object.create(null))console.log({})结果图 根据结果我们不难发现&#xff0c;两者最大区别在于Object.create(null)创建的对象没有继承Object 所有Object.create(null)创建的对象也没有Object提供的方法&#xff0c;是一个非常纯净的对象 ps: Object.create(obj…

matplotlib —— 添加文本信息(text)

matplotlib.pyplot.text(x, y, s, fontdictNone, withdashFalse, **kwargs) x, y&#xff1a;表示坐标&#xff1b;s&#xff1a;字符串文本&#xff1b;fontdict&#xff1a;字典&#xff0c;可选&#xff1b;kw&#xff1a; fontsize12,horizontalalignment‘center’、ha’c…

值得推荐的C/C++框架和库 (真的很强大)

From: https://blog.csdn.net/u011628751/article/details/69258637/ 值得学习的C语言开源项目 - 1. Webbench Webbench是一个在Linux下使用的非常简单的网站压测工具。它使用fork()模拟多个客户端同时访问我们设定的URL&#xff0c;测试网站在压力下工作的性能&#xff0c;…

java web 中的转发和重定向路径问题

为什么80%的码农都做不了架构师&#xff1f;>>> 假设应用程序的 contextPath 为 /ctx&#xff0c;在 http://localhost:8080/ctx/a/b 资源中&#xff0c;我们转发和重定向到 http://localhost:8080/ctx/x/y 资源&#xff0c;分别应该怎么写&#xff1f; 转发&…

断言assert使用方法

测试代码 console.log(开始)console.assert(true, true)console.assert(false,false)console.log(结束)结果 可以发现&#xff1a; assert方法中&#xff0c;第一个参数是判断条件&#xff0c;当为true时&#xff0c;不执行 。当为false时&#xff0c; 输出后面提示内容 且我们…