웹 소켓 프레임 연구

오늘 tomcat 소스 코드 를 보 았 을 때 websocket 을 보 았 습 니 다. 예전 에 phop 에서 websocket 을 만 들 때 도 연 구 했 지만 frame 은 바이트 와 과거 가 바로 무시 되 었 습 니 다. 오늘 은 다시 연 구 했 습 니 다.
웹 소켓 의 프로 토 콜 은 RFC 6455 에 있 습 니 다. 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();
    }

다음으로 전송:https://www.cnblogs.com/imayi/archive/2012/05/05/2485343.html

좋은 웹페이지 즐겨찾기