C++实现websocket服务器握手协议(使用Qt)

6 篇文章 1 订阅
2 篇文章 0 订阅
本文介绍了如何在C++中利用Qt库实现WebSocket的握手协议。内容包括识别和处理WebSocket的第一个握手包,获取并解析`Sec-WebSocket-Key`,结合固定字符串进行SHA1和Base64编码,以完成服务器的响应。代码示例展示了实现过程,并提到在实际应用中还需处理后续数据的解析和粘包问题。
摘要由CSDN通过智能技术生成

前提:笔者在开发server程序时,要求websocket与server连接

websocket的机制是在第一次连接时进行握手协议,协议通过,才可以进行正常的通信,否则websocket就会断开连接;

下面就是websocket第一次发送的握手包:

GET / HTTP/1.1\r\n
Host: 192.168.5.24:17913\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0\r\n
Accept: */*\r\n
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\r\n
Accept-Encoding: gzip, deflate\r\n
Sec-WebSocket-Version: 13\r\n
Origin: http://127.0.0.1:8848\r\n
Sec-WebSocket-Extensions: permessage-deflate\r\n
Sec-WebSocket-Key: tepG0DQZtEJ7MLbw7kbewA==\r\n
Connection: keep-alive, Upgrade\r\n
Pragma: no-cache\r\nCache-Control: no-cache\r\n
Upgrade: websocket\r\n\r\n

那需要对websocket发送来的第一个数据进行处理(判断是否是第一个包,可以通过开头GET来进行判断,可能不是非常严谨),获取Sec-WebSocket-Key的值(也就是上面的ikLk+bBgZDQRPTOBAzGsBg==),然后对此进行解析。

解析的方法是在key上加上固定字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,再进行sha1解码及base64编码,然后打包发送给websocket客户端。

返回的握手包如下:

HTTP/1.1 101 Switching Protocols\r\n
Connection: upgrade\r\n
Sec-WebSocket-Accept: mhW8gChbFWgUKJxpzcbPlcwJxcw=\r\n
Upgrade: websocket\r\n\r\n

代码如下:

void rcvReadData()
{
    QByteArray data_ = this->readAll();//socket接收数据
    if(!_firstConnect)//第一个包
    {
        _firstConnect = true;
        QString qstr_ = data_;//包数据转化成QString
        QString key_ = "";
        key_ = getKey(qstr_);
        if(key_ == "-1")
        {
            //自定义处理
        }
        else if(key_ == "-2")
        {
            //自定义处理
        }
        else
        {
            //处理key
            char request[1024] = "";  //请求信息
            respondHandshake(request,key_.toStdString());
            QByteArray array_(request);
            write(array_);//发送数据给websocket客户端
        }
    }
    else
    {
        //接下来包在此不做处理,需要涉及到websocket协议的解包
    }
}

/**
*获取Sec-WebSocket-Key的值,QT实现
*/
QString getKey(QString qstr)
{
    int i = qstr.indexOf("GET");
    if(i < 0)
    {
        return "-1";
    }
    int j = qstr.indexOf("Sec-WebSocket-Key");
    if(j < 0)
    {
        return "-2";
    }
    QString key = qstr.mid(j + 19, 24);
    return key;
}

/**
*获取Sec-WebSocket-Key的值,C++实现
*/
string getKey(string str)
{
    int i = str.find("GET");
    if(i < 0)
    {
        return "-1";
    }
    int j = str.find("Sec-WebSocket-Key");
    if(j < 0)
    {
        return "-2";
    }
    string key = str.substr(j + 19, 24);
    return key;
}

void respondHandshake(char *request, string clientkey)
{
    strcat(request, "HTTP/1.1 101 Switching Protocols\r\n");
    strcat(request, "Connection: upgrade\r\n");
    strcat(request, "Sec-WebSocket-Accept: ");
    string server_key = clientkey;
    server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    SHA1  sha;
    unsigned int message_digest[5];
    cout <<"server_key:"<< server_key << endl;
    sha.Reset();

    sha << server_key.c_str();
    sha.Result(message_digest);
    for (int i = 0; i < 5; i++) {
        message_digest[i] = htonl(message_digest[i]);
    }
    base64 base64_;
    server_key = base64_.base64_encode(reinterpret_cast<const unsigned char*>(message_digest), 20);
    server_key += "\r\n";
    strcat(request, server_key.c_str());
    strcat(request, "Upgrade: websocket\r\n\r\n");
}

至于代码中出现的sha1以及base64,,可以在以下链接中找到,本文就不再复制粘贴了:

C++简单实现一个websocket服务器_c++ websocket server-CSDN博客

以上只是对握手协议进行了实现,但是实际使用中,在握手完成后,对于websocket发送来的数据,还需要进行解析,才可以获取数据,而且在解析时,还需要处理粘包半包等问题,留待下一篇文章进行阐述。

解析发送的数据,见我下一章:C++实现WebSocket解析协议

结尾:

只为记录,只为分享! 愿所写能对你有所帮助。不忘记点个赞,谢谢~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值