zoukankan      html  css  js  c++  java
  • Qt websocket协议的实现

     
    handshake(握手)
    client请求:
         GET /chat HTTP/1.1
            Host: server.example.com
            Upgrade: websocket
            Connection: Upgrade
            Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
            Sec-WebSocket-Version: 13
    server回复:
         HTTP/1.1 101 Switching Protocols
            Upgrade: websocket
            Connection: Upgrade
            Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

    "dGhlIHNhbXBsZSBub25jZQ=="(Sec-WebSocket-Key)+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"(因定GUID)
    先SHA-1哈希,再用base64编码,得到"s3pPLMBiTxaQ9kYGzzhZRbK+xOo="

    Framing Protocol(数据帧协议)
          0                   1                   2                   3
          0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
         +-+-+-+-+-------+-+-------------+-------------------------------+
         |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
         |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
         |N|V|V|V|       |S|             |   (if payload len==126/127)   |
         | |1|2|3|       |K|             |                               |
         +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
         |     Extended payload length continued, if payload len == 127  |
         + - - - - - - - - - - - - - - - +-------------------------------+
         |                               |Masking-key, if MASK set to 1  |
         +-------------------------------+-------------------------------+
         | Masking-key (continued)       |          Payload Data         |
         +-------------------------------- - - - - - - - - - - - - - - - +
         :                     Payload Data continued ...                :
         + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
         |                     Payload Data continued ...                |
         +---------------------------------------------------------------+
    opcode:
         0x1 text frame
         0x2 binary frame
         0x8 connection close
    Mask:是否有掩码(client to server必须, server to client可选)
    Payload length:负载长度
         <=125 直接7位表示长度
         126,表示长充大于125并小于0xFFFF,长度放在2Byte
         127,长度放在后8Byte
    Masking-key:如果有Mask,4Byte
    Payload Data:如果有Mask,需要和Making-key做异或来还原数据
     
    附WebSocket Protocol
    http://datatracker.ietf.org/doc/rfc6455/?include_text=1
     
     
    代码

    QByteArray handShake(QString secWebSocketKey)
    {
        Q_ASSERT(!secWebSocketKey.isEmpty());
        secWebSocketKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        QString s=  QCryptographicHash::hash(secWebSocketKey.toAscii(),
                                             QCryptographicHash::Sha1).toBase64();
        QString respone = QString("HTTP/1.1 101 Switching Protocols "
                                  "Upgrade: websocket "
                                  "Connection: Upgrade "
                                  "Access-Control-Allow-Credentials:true "
                                  "Access-Control-Allow-Headers:content-type "
                                  "Sec-WebSocket-Accept: %1 "
                                  " ").arg(s);
        return respone.toAscii();
    }

        
    void unmask (int pos, int len, unsigned char *buf)
    {
        int i = pos;                //The position of payload data
        int n = pos - 4;            //The position of masking-key
        for (; i<len; i++,n++)
        {
            if (n == pos) n = pos - 4;  //back to the first masking-key
            buf[i] ^= buf[n];       //unmask: payload data XOR masking-key
        }
    }

    QByteArray parserData(QByteArray input)
    {
        unsigned char *buf=(unsigned char *)input.data();
        QByteArray out;
        int len = input.length();
        if (buf[0] == 0x88)
        {
            qDebug()<<"Received a Close frame";
            out = "close";
            return out;
        }
        buf[1] &= 0x7F;
        int payloadBegin = 0;

        if (buf[1] < 126)
        {
            payloadBegin = 6;
        }
        else if (buf[1] == 126)
        {
            payloadBegin = 8; //6+2
        }
        else if (buf[1] == 127)
        {
            payloadBegin = 14;//6+8
        }
        unmask(payloadBegin, len, buf);
      
        out = QByteArray::fromRawData((const char *)(input.data()+payloadBegin), input.size()-payloadBegin);
        return out;
    }

    void writeData(QTcpSocket *socket, const QByteArray &data)
    {
        QByteArray head(2, 0);
        if (data.length()<=125)
        {
            quint8 len = data.length();
            head[1] = len;
        }
        else if (data.length()<=0xffff)
        {
            head[1] = 126;

            quint16 len = data.length();
            head.resize(4);
            for (int i=3; i>1; i--)
            {
                head[i] = (byte)(len & 0xff);
                len = len >> 8;
            }
        }
        else{
            head[1] = 127;
            quint64 len = data.length();
            head.resize(10);
            for (int i=9; i>1; i--)
            {
                head[i] = (byte)(len & 0xff);
                len = len >> 8;
            }
        }
        socket->write(head);
        socket->write(data);
        socket->flush();
    }
  • 相关阅读:
    LIBTIFF 配置 (vs2010 + win8 + 32位 )
    minGW、cygwin、gnuwin32 介绍
    LabVIEW发布功能总结
    LabVIEW新手5大错误
    专业功放测试:主要性能指标&信噪比测量
    常用低压电器的主要种类和用途
    LabVIEW是一种通用的编程语言吗?
    LabVIEW TCP/IP 断开重连问题
    LabVIEW 的bool(布尔)按键机械属性
    LabVIEW 远程控制VI
  • 原文地址:https://www.cnblogs.com/danju/p/3691643.html
Copyright © 2011-2022 走看看