websocket Frame研究

来源:互联网 发布:现在民办学校域名注册 编辑:程序博客网 时间:2024/05/22 16:47

今天看tomcat 源码的时候看见websocket了,之前在php弄websocket的时候也研究了一下,不过它的frame一看是字节与过来与过去直接就无视了,今天又重新研究了一下。

websocket 的协议在RFC6455中  http://tools.ietf.org/html/rfc6455#section-5.1

复制代码
 帧格式为:
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 ... | +---------------------------------------------------------------+
复制代码
    FIN:  1 bit      Indicates that this is the final fragment in a message.  The first      fragment MAY also be the final fragment.    RSV1, RSV2, RSV3:  1 bit each      MUST be 0 unless an extension is negotiated that defines meanings      for non-zero values.  If a nonzero value is received and none of      the negotiated extensions defines the meaning of such a nonzero      value, the receiving endpoint MUST _Fail the WebSocket      Connection_.
   Opcode:  4 bits      Defines the interpretation of the "Payload data".  If an unknown      opcode is received, the receiving endpoint MUST _Fail the      WebSocket Connection_.  The following values are defined.
   Mask:  1 bit
     Defines whether the "Payload data" is masked.  If set to 1, a      masking key is present in masking-key, and this is used to unmask      the "Payload data" .  All frames sent from      client to server have this bit set to 1
   Payload length:  7 bits, 7+16 bits, or 7+64 bits      The length of the "Payload data", in bytes: if 0-125, that is the      payload length.  If 126, the following 2 bytes interpreted as a      16-bit unsigned integer are the payload length.  If 127, the      following 8 bytes interpreted as a 64-bit unsigned integer (the      most significant bit MUST be 0) are the payload length.  Multibyte      length quantities are expressed in network byte order.  Note that      in all cases, the minimal number of bytes MUST be used to encode      the length, for example, the length of a 124-byte-long string      can't be encoded as the sequence 126, 0, 124.  The payload length      is the length of the "Extension data" + the length of the      "Application data".  The length of the "Extension data" may be      zero, in which case the payload length is the length of the      "Application data".
    Masking-key:  0 or 4 bytes      All frames sent from the client to the server are masked by a      32-bit value that is contained within the frame.  This field is      present if the mask bit is set to 1 and is absent if the mask bit      is set to 0.  See Section 5.3 for further information on client-      to-server masking.    Payload data:  (x+y) bytes      The "Payload data" is defined as "Extension data" concatenated      with "Application data".   Extension data:  x bytes      The "Extension data" is 0 bytes unless an extension has been      negotiated.  Any extension MUST specify the length of the      "Extension data", or how that length may be calculated, and how      the extension use MUST be negotiated during the opening handshake.      If present, the "Extension data" is included in the total payload      length.   Application data:  y bytes      Arbitrary "Application data", taking up the remainder of the frame      after any "Extension data".  The length of the "Application data"      is equal to the payload length minus the length of the "Extension      data".

下面是tomcat中的WSFrame类,在org\apache\catalina\websocket 中
复制代码
 private WsFrame(byte first,            UpgradeProcessor<?> processor) throws IOException {                                        //RFC6455文档解释了frame的格式 http://tools.ietf.org/html/rfc6455#section-5.1        int b = first & 0xFF;           //转换成32位        fin = (b & 0x80) > 0;           //得到第8位 10000000>0        rsv = (b & 0x70) >>> 4;         //得到5、6、7 为01110000 然后右移四位为00000111        opCode = (byte) (b & 0x0F);     //后四位为opCode 00001111        b = blockingRead(processor);    //向后读取一个字节        // Client data must be masked        if ((b & 0x80) == 0) {          //第9为为mask,必须为1            throw new IOException(sm.getString("frame.notMasked"));        }        payloadLength = b & 0x7F;       //读取后7位  Payload legth,如果为125则payloadLength         if (payloadLength == 126) {     //为126读2个字节,后两个字节为payloadLength            byte[] extended = new byte[2];            blockingRead(processor, extended);            payloadLength = Conversions.byteArrayToLong(extended); //读取的2个字节转换成LONG类型        } else if (payloadLength == 127) {  //127读8个字节,后8个字节为payloadLength            byte[] extended = new byte[8];            blockingRead(processor, extended);            payloadLength = Conversions.byteArrayToLong(extended);//8个字节转换成LONG        }        if (isControl()) {            if (payloadLength > 125) {                throw new IOException();            }            if (!fin) {                throw new IOException();            }        }        blockingRead(processor, mask);//接着为MASK-KEY:0or4个字节,mask为1读4个字节        if (isControl()) {            // Note: Payload limited to <= 125 bytes by test above            payload = ByteBuffer.allocate((int) payloadLength);            blockingRead(processor, payload);  //读取payloadLength个字节长度放进payload            if (opCode == Constants.OPCODE_CLOSE && payloadLength > 2) {                // Check close payload - if present - is valid UTF-8                CharBuffer cb = CharBuffer.allocate((int) payloadLength);                Utf8Decoder decoder = new Utf8Decoder();     //将字节解码成UTF-8格式                payload.position(2);                CoderResult cr = decoder.decode(payload, cb, true);//从第3个开始                payload.position(0);                if (cr.isError()) {                    throw new IOException(sm.getString("frame.invalidUtf8"));                }            }        } else {            payload = null;        }    }
复制代码
复制代码
  private int blockingRead(UpgradeProcessor<?> processor)            throws IOException {        int result = processor.read();        if (result == -1) {            throw new IOException(sm.getString("frame.eos"));        }        return result;    }    /*     * Blocks until the byte array has been filled.     */    private void blockingRead(UpgradeProcessor<?> processor, byte[] bytes)  //向后读bytes.length个字节            throws IOException {        int read = 0;        int last = 0;        while (read < bytes.length) {            last = processor.read(true, bytes, read, bytes.length - read);            if (last == -1) {                throw new IOException(sm.getString("frame.eos"));            }            read += last;        }    }    /*     * Intended to read whole payload and blocks until it has. Therefore able to     * unmask the payload data.     */    private void blockingRead(UpgradeProcessor<?> processor, ByteBuffer bb)            throws IOException {        int last = 0;        while (bb.hasRemaining()) {            last = processor.read();            if (last == -1) {                throw new IOException(sm.getString("frame.eos"));            }            bb.put((byte) (last ^ mask[bb.position() % 4]));        }        bb.flip();    }
复制代码
标签: java, websoket
0 0
原创粉丝点击