代码之家  ›  专栏  ›  技术社区  ›  Community wiki

如何在服务器端发送和接收WebSocket消息?

  •  91
  • Community wiki  · 技术社区  · 3 年前
    • 根据协议,我如何使用WebSocket在服务器端发送和接收消息?

    • 当我从浏览器向服务器发送数据时,为什么我在服务器上得到看似随机的字节?数据是以某种方式编码的吗?

    • 框架如何在两个服务器中工作→ 客户和客户→ 服务器方向?

    13 回复  |  直到 14 年前
        1
  •  161
  •   pimvdb    4 年前

    注意:这是关于如何实现一个非常琐碎的服务器的一些解释和伪代码,该服务器可以根据最终的帧格式处理传入和传出的WebSocket消息。它不包括握手过程。此外,这一回答是出于教育目的;它不是一个功能齐全的实现。

    Specification (RFC 6455)


    发送消息

    (换句话说,服务器浏览器)

    您发送的帧需要根据WebSocket帧格式进行格式化。对于发送消息,此格式如下:

    • 一个字节,包含数据类型(以及一些超出普通服务器范围的附加信息)
    • 一个包含长度的字节
    • 如果长度不适合第二个字节,则为两个或八个字节(第二个是一个代码,说明长度使用了多少字节)
    • 实际(原始)数据

    第一个字节将是 1000 0001 (或 129 )用于文本框。

    第二个字节的第一位设置为 0 因为我们没有对数据进行编码(从服务器到客户端的编码不是强制性的)。

    有必要确定原始数据的长度,以便正确发送长度字节:

    • 如果 0 <= length <= 125 ,不需要额外的字节
    • 如果 126 <= length <= 65535 ,您需要两个额外的字节,第二个字节是 126
    • 如果 length >= 65536 ,您需要另外八个字节,第二个字节是 127

    长度必须被分割成单独的字节,这意味着你需要向右移位(数量为8位),然后只保留最后8位 AND 1111 1111 (即 255 )。

    长度字节之后是原始数据。

    这将导致以下伪代码:

    bytesFormatted[0] = 129
    
    indexStartRawData = -1 // it doesn't matter what value is
                           // set here - it will be set now:
    
    if bytesRaw.length <= 125
        bytesFormatted[1] = bytesRaw.length
    
        indexStartRawData = 2
    
    else if bytesRaw.length >= 126 and bytesRaw.length <= 65535
        bytesFormatted[1] = 126
        bytesFormatted[2] = ( bytesRaw.length >> 8 ) AND 255
        bytesFormatted[3] = ( bytesRaw.length      ) AND 255
    
        indexStartRawData = 4
    
    else
        bytesFormatted[1] = 127
        bytesFormatted[2] = ( bytesRaw.length >> 56 ) AND 255
        bytesFormatted[3] = ( bytesRaw.length >> 48 ) AND 255
        bytesFormatted[4] = ( bytesRaw.length >> 40 ) AND 255
        bytesFormatted[5] = ( bytesRaw.length >> 32 ) AND 255
        bytesFormatted[6] = ( bytesRaw.length >> 24 ) AND 255
        bytesFormatted[7] = ( bytesRaw.length >> 16 ) AND 255
        bytesFormatted[8] = ( bytesRaw.length >>  8 ) AND 255
        bytesFormatted[9] = ( bytesRaw.length       ) AND 255
    
        indexStartRawData = 10
    
    // put raw data at the correct index
    bytesFormatted.put(bytesRaw, indexStartRawData)
    
    
    // now send bytesFormatted (e.g. write it to the socket stream)
    

    正在接收消息

    (换句话说,浏览器服务器)

    您获得的帧采用以下格式:

    • 一个包含数据类型的字节
    • 一个包含长度的字节
    • 如果长度不适合第二个字节,则增加两个或八个字节
    • 作为掩码的四个字节(=解码密钥)
    • 实际数据

    第一个字节通常并不重要——如果你只是发送文本,那么你只使用文本类型。会的 1000 0001 (或 129 )在这种情况下。

    第二个字节和另外的两个或八个字节需要一些解析,因为您需要知道长度使用了多少字节(您需要知道实际数据从哪里开始)。长度本身通常是不必要的,因为您已经有了数据。

    第二个字节的第一位总是 1 这意味着数据被屏蔽(=编码)。从客户端到服务器的消息总是被屏蔽的。你需要通过做 secondByte AND 0111 1111 有两种情况下,结果字节不表示长度,因为它不适合第二个字节:

    • 的第二个字节 0111 1110 126 ,表示长度使用以下两个字节
    • 的第二个字节 0111 1111 127 ,表示以下八个字节用于长度

    四个掩码字节用于对已发送的实际数据进行解码。解码算法如下:

    decodedByte = encodedByte XOR masks[encodedByteIndex MOD 4]
    

    哪里 encodedByte 是数据中的原始字节, encodedByteIndex 是从第一个字节开始计数的字节的索引(偏移量) 真实数据的 ,具有索引 0 masks 是包含四个掩码字节的数组。

    这导致以下用于解码的伪代码:

    secondByte = bytes[1]
    
    length = secondByte AND 127 // may not be the actual length in the two special cases
    
    indexFirstMask = 2          // if not a special case
    
    if length == 126            // if a special case, change indexFirstMask
        indexFirstMask = 4
    
    else if length == 127       // ditto
        indexFirstMask = 10
    
    masks = bytes.slice(indexFirstMask, 4) // four bytes starting from indexFirstMask
    
    indexFirstDataByte = indexFirstMask + 4 // four bytes further
    
    decoded = new array
    
    decoded.length = bytes.length - indexFirstDataByte // length of real data
    
    for i = indexFirstDataByte, j = 0; i < bytes.length; i++, j++
        decoded[j] = bytes[i] XOR masks[j MOD 4]
    
    
    // now use "decoded" to interpret the received data
    
        2
  •  25
  •   Haribabu Pasupathy    11 年前

    Java实现(如果有人需要)

    正在读取:客户端到服务器

            int len = 0;            
            byte[] b = new byte[buffLenth];
            //rawIn is a Socket.getInputStream();
            while(true){
                len = rawIn.read(b);
                if(len!=-1){
    
                    byte rLength = 0;
                    int rMaskIndex = 2;
                    int rDataStart = 0;
                    //b[0] is always text in my case so no need to check;
                    byte data = b[1];
                    byte op = (byte) 127;
                    rLength = (byte) (data & op);
    
                    if(rLength==(byte)126) rMaskIndex=4;
                    if(rLength==(byte)127) rMaskIndex=10;
    
                    byte[] masks = new byte[4];
    
                    int j=0;
                    int i=0;
                    for(i=rMaskIndex;i<(rMaskIndex+4);i++){
                        masks[j] = b[i];
                        j++;
                    }
    
                    rDataStart = rMaskIndex + 4;
    
                    int messLen = len - rDataStart;
    
                    byte[] message = new byte[messLen];
    
                    for(i=rDataStart, j=0; i<len; i++, j++){
                        message[j] = (byte) (b[i] ^ masks[j % 4]);
                    }
    
                    parseMessage(new String(message)); 
                    //parseMessage(new String(b));
    
                    b = new byte[buffLenth];
    
                }
            }
    

    写入:服务器到客户端

    public void brodcast(String mess) throws IOException{
        byte[] rawData = mess.getBytes();
    
        int frameCount  = 0;
        byte[] frame = new byte[10];
    
        frame[0] = (byte) 129;
    
        if(rawData.length <= 125){
            frame[1] = (byte) rawData.length;
            frameCount = 2;
        }else if(rawData.length >= 126 && rawData.length <= 65535){
            frame[1] = (byte) 126;
            int len = rawData.length;
            frame[2] = (byte)((len >> 8 ) & (byte)255);
            frame[3] = (byte)(len & (byte)255); 
            frameCount = 4;
        }else{
            frame[1] = (byte) 127;
            int len = rawData.length;
            frame[2] = (byte)((len >> 56 ) & (byte)255);
            frame[3] = (byte)((len >> 48 ) & (byte)255);
            frame[4] = (byte)((len >> 40 ) & (byte)255);
            frame[5] = (byte)((len >> 32 ) & (byte)255);
            frame[6] = (byte)((len >> 24 ) & (byte)255);
            frame[7] = (byte)((len >> 16 ) & (byte)255);
            frame[8] = (byte)((len >> 8 ) & (byte)255);
            frame[9] = (byte)(len & (byte)255);
            frameCount = 10;
        }
    
        int bLength = frameCount + rawData.length;
    
        byte[] reply = new byte[bLength];
    
        int bLim = 0;
        for(int i=0; i<frameCount;i++){
            reply[bLim] = frame[i];
            bLim++;
        }
        for(int i=0; i<rawData.length;i++){
            reply[bLim] = rawData[i];
            bLim++;
        }
    
        out.write(reply);
        out.flush();
    
    }
    
        3
  •  18
  •   conceptDawg    14 年前

    JavaScript实现:

    function encodeWebSocket(bytesRaw){
        var bytesFormatted = new Array();
        bytesFormatted[0] = 129;
        if (bytesRaw.length <= 125) {
            bytesFormatted[1] = bytesRaw.length;
        } else if (bytesRaw.length >= 126 && bytesRaw.length <= 65535) {
            bytesFormatted[1] = 126;
            bytesFormatted[2] = ( bytesRaw.length >> 8 ) & 255;
            bytesFormatted[3] = ( bytesRaw.length      ) & 255;
        } else {
            bytesFormatted[1] = 127;
            bytesFormatted[2] = ( bytesRaw.length >> 56 ) & 255;
            bytesFormatted[3] = ( bytesRaw.length >> 48 ) & 255;
            bytesFormatted[4] = ( bytesRaw.length >> 40 ) & 255;
            bytesFormatted[5] = ( bytesRaw.length >> 32 ) & 255;
            bytesFormatted[6] = ( bytesRaw.length >> 24 ) & 255;
            bytesFormatted[7] = ( bytesRaw.length >> 16 ) & 255;
            bytesFormatted[8] = ( bytesRaw.length >>  8 ) & 255;
            bytesFormatted[9] = ( bytesRaw.length       ) & 255;
        }
        for (var i = 0; i < bytesRaw.length; i++){
            bytesFormatted.push(bytesRaw.charCodeAt(i));
        }
        return bytesFormatted;
    }
    
    function decodeWebSocket (data){
        var datalength = data[1] & 127;
        var indexFirstMask = 2;
        if (datalength == 126) {
            indexFirstMask = 4;
        } else if (datalength == 127) {
            indexFirstMask = 10;
        }
        var masks = data.slice(indexFirstMask,indexFirstMask + 4);
        var i = indexFirstMask + 4;
        var index = 0;
        var output = "";
        while (i < data.length) {
            output += String.fromCharCode(data[i++] ^ masks[index++ % 4]);
        }
        return output;
    }
    
        4
  •  13
  •   Nitij    11 年前

    C#实现

    浏览器->服务器

        private String DecodeMessage(Byte[] bytes)
        {
            String incomingData = String.Empty;
            Byte secondByte = bytes[1];
            Int32 dataLength = secondByte & 127;
            Int32 indexFirstMask = 2;
            if (dataLength == 126)
                indexFirstMask = 4;
            else if (dataLength == 127)
                indexFirstMask = 10;
    
            IEnumerable<Byte> keys = bytes.Skip(indexFirstMask).Take(4);
            Int32 indexFirstDataByte = indexFirstMask + 4;
    
            Byte[] decoded = new Byte[bytes.Length - indexFirstDataByte];
            for (Int32 i = indexFirstDataByte, j = 0; i < bytes.Length; i++, j++)
            {
                decoded[j] = (Byte)(bytes[i] ^ keys.ElementAt(j % 4));
            }
    
            return incomingData = Encoding.UTF8.GetString(decoded, 0, decoded.Length);
        }
    

    服务器->浏览器

        private static Byte[] EncodeMessageToSend(String message)
        {
            Byte[] response;
            Byte[] bytesRaw = Encoding.UTF8.GetBytes(message);
            Byte[] frame = new Byte[10];
    
            Int32 indexStartRawData = -1;
            Int32 length = bytesRaw.Length;
    
            frame[0] = (Byte)129;
            if (length <= 125)
            {
                frame[1] = (Byte)length;
                indexStartRawData = 2;
            }
            else if (length >= 126 && length <= 65535)
            {
                frame[1] = (Byte)126;
                frame[2] = (Byte)((length >> 8) & 255);
                frame[3] = (Byte)(length & 255);
                indexStartRawData = 4;
            }
            else
            {
                frame[1] = (Byte)127;
                frame[2] = (Byte)((length >> 56) & 255);
                frame[3] = (Byte)((length >> 48) & 255);
                frame[4] = (Byte)((length >> 40) & 255);
                frame[5] = (Byte)((length >> 32) & 255);
                frame[6] = (Byte)((length >> 24) & 255);
                frame[7] = (Byte)((length >> 16) & 255);
                frame[8] = (Byte)((length >> 8) & 255);
                frame[9] = (Byte)(length & 255);
    
                indexStartRawData = 10;
            }
    
            response = new Byte[indexStartRawData + length];
    
            Int32 i, reponseIdx = 0;
    
            //Add the frame bytes to the reponse
            for (i = 0; i < indexStartRawData; i++)
            {
                response[reponseIdx] = frame[i];
                reponseIdx++;
            }
    
            //Add the data bytes to the response
            for (i = 0; i < length; i++)
            {
                response[reponseIdx] = bytesRaw[i];
                reponseIdx++;
            }
    
            return response;
        }
    
        5
  •  6
  •   Hunter Fernandes    14 年前

    pimvdb的答案在python中实现:

    def DecodedCharArrayFromByteStreamIn(stringStreamIn):
        #turn string values into opererable numeric byte values
        byteArray = [ord(character) for character in stringStreamIn]
        datalength = byteArray[1] & 127
        indexFirstMask = 2 
        if datalength == 126:
            indexFirstMask = 4
        elif datalength == 127:
            indexFirstMask = 10
        masks = [m for m in byteArray[indexFirstMask : indexFirstMask+4]]
        indexFirstDataByte = indexFirstMask + 4
        decodedChars = []
        i = indexFirstDataByte
        j = 0
        while i < len(byteArray):
            decodedChars.append( chr(byteArray[i] ^ masks[j % 4]) )
            i += 1
            j += 1
        return decodedChars
    

    用法示例:

    fromclient = '\x81\x8c\xff\xb8\xbd\xbd\xb7\xdd\xd1\xd1\x90\x98\xea\xd2\x8d\xd4\xd9\x9c'
    # this looks like "?ŒOÇ¿¢gÓ ç\Ð=«ož" in unicode, received by server
    print DecodedCharArrayFromByteStreamIn(fromclient)
    # ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!']
    
        6
  •  5
  •   Tacticus    11 年前

    除了PHP帧编码函数外,下面还有一个解码函数:

    function Decode($M){
        $M = array_map("ord", str_split($M));
        $L = $M[1] AND 127;
    
        if ($L == 126)
            $iFM = 4;
        else if ($L == 127)
            $iFM = 10;
        else
            $iFM = 2;
    
        $Masks = array_slice($M, $iFM, 4);
    
        $Out = "";
        for ($i = $iFM + 4, $j = 0; $i < count($M); $i++, $j++ ) {
            $Out .= chr($M[$i] ^ $Masks[$j % 4]);
        }
        return $Out;
    }
    

    我已经在一个易于使用的WebSocket PHP类中实现了这个以及其他函数 here

        7
  •  4
  •   DanBlack    11 年前

    PHP实现:

    function encode($message)
    {
        $length = strlen($message);
    
        $bytesHeader = [];
        $bytesHeader[0] = 129; // 0x1 text frame (FIN + opcode)
    
        if ($length <= 125) {
                $bytesHeader[1] = $length;
        } else if ($length >= 126 && $length <= 65535) {
                $bytesHeader[1] = 126;
                $bytesHeader[2] = ( $length >> 8 ) & 255;
                $bytesHeader[3] = ( $length      ) & 255;
        } else {
                $bytesHeader[1] = 127;
                $bytesHeader[2] = ( $length >> 56 ) & 255;
                $bytesHeader[3] = ( $length >> 48 ) & 255;
                $bytesHeader[4] = ( $length >> 40 ) & 255;
                $bytesHeader[5] = ( $length >> 32 ) & 255;
                $bytesHeader[6] = ( $length >> 24 ) & 255;
                $bytesHeader[7] = ( $length >> 16 ) & 255;
                $bytesHeader[8] = ( $length >>  8 ) & 255;
                $bytesHeader[9] = ( $length       ) & 255;
        }
    
        $str = implode(array_map("chr", $bytesHeader)) . $message;
    
        return $str;
    }
    
        8
  •  4
  •   DR.    11 年前

    谢谢你的回答,我想补充一下 hfern的 (上图)Python版本,如果有人感兴趣,可以包含Sending函数。

    def DecodedWebsockRecieve(stringStreamIn):
        byteArray =  stringStreamIn 
        datalength = byteArray[1] & 127
        indexFirstMask = 2 
        if datalength == 126:
            indexFirstMask = 4
        elif datalength == 127:
            indexFirstMask = 10
        masks = [m for m in byteArray[indexFirstMask : indexFirstMask+4]]
        indexFirstDataByte = indexFirstMask + 4
        decodedChars = []
        i = indexFirstDataByte
        j = 0
        while i < len(byteArray):
            decodedChars.append( chr(byteArray[i] ^ masks[j % 4]) )
            i += 1
            j += 1
        return ''.join(decodedChars)
    
    def EncodeWebSockSend(socket,data):
        bytesFormatted = []
        bytesFormatted.append(129)
    
        bytesRaw = data.encode()
        bytesLength = len(bytesRaw)
        if bytesLength <= 125 :
            bytesFormatted.append(bytesLength)
        elif bytesLength >= 126 and bytesLength <= 65535 :
            bytesFormatted.append(126)
            bytesFormatted.append( ( bytesLength >> 8 ) & 255 )
            bytesFormatted.append( bytesLength & 255 )
        else :
            bytesFormatted.append( 127 )
            bytesFormatted.append( ( bytesLength >> 56 ) & 255 )
            bytesFormatted.append( ( bytesLength >> 48 ) & 255 )
            bytesFormatted.append( ( bytesLength >> 40 ) & 255 )
            bytesFormatted.append( ( bytesLength >> 32 ) & 255 )
            bytesFormatted.append( ( bytesLength >> 24 ) & 255 )
            bytesFormatted.append( ( bytesLength >> 16 ) & 255 )
            bytesFormatted.append( ( bytesLength >>  8 ) & 255 )
            bytesFormatted.append( bytesLength & 255 )
    
        bytesFormatted = bytes(bytesFormatted)
        bytesFormatted = bytesFormatted + bytesRaw
        socket.send(bytesFormatted) 
    

    阅读用途:

    bufSize = 1024     
    read = DecodedWebsockRecieve(socket.recv(bufSize))
    

    书写用法:

    EncodeWebSockSend(sock,"hellooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo")
    
        9
  •  2
  •   rmonjo    12 年前

    围棋中的实施

    编码部件(服务器->浏览器)

    func encode (message string) (result []byte) {
      rawBytes := []byte(message)
      var idxData int
    
      length := byte(len(rawBytes))
      if len(rawBytes) <= 125 { //one byte to store data length
        result = make([]byte, len(rawBytes) + 2)
        result[1] = length
        idxData = 2
      } else if len(rawBytes) >= 126 && len(rawBytes) <= 65535 { //two bytes to store data length
        result = make([]byte, len(rawBytes) + 4)
        result[1] = 126 //extra storage needed
        result[2] = ( length >> 8 ) & 255
        result[3] = ( length      ) & 255
        idxData = 4
      } else {
        result = make([]byte, len(rawBytes) + 10)
        result[1] = 127
        result[2] = ( length >> 56 ) & 255
        result[3] = ( length >> 48 ) & 255
        result[4] = ( length >> 40 ) & 255
        result[5] = ( length >> 32 ) & 255
        result[6] = ( length >> 24 ) & 255
        result[7] = ( length >> 16 ) & 255
        result[8] = ( length >>  8 ) & 255
        result[9] = ( length       ) & 255
        idxData = 10
      }
    
      result[0] = 129 //only text is supported
    
      // put raw data at the correct index
      for i, b := range rawBytes {
        result[idxData + i] = b
      }
      return
    }
    

    解码部分(浏览器->服务器)

    func decode (rawBytes []byte) string {
      var idxMask int
      if rawBytes[1] == 126 {
        idxMask = 4
      } else if rawBytes[1] == 127 {
        idxMask = 10
      } else {
        idxMask = 2
      }
    
      masks := rawBytes[idxMask:idxMask + 4]
      data := rawBytes[idxMask + 4:len(rawBytes)]
      decoded := make([]byte, len(rawBytes) - idxMask + 4)
    
      for i, b := range data {
        decoded[i] = b ^ masks[i % 4]
      }
      return string(decoded)
    }
    
        10
  •  2
  •   scape    12 年前

    Clojure,decode函数假设帧作为的映射发送 {:data byte-array-buffer :size int-size-of-buffer} ,因为实际大小可能与字节数组的大小不同,这取决于输入流的块大小。

    此处发布的代码: https://gist.github.com/viperscape/8918565

    (defn ws-decode [frame]
      "decodes websocket frame"
      (let [data (:data frame)
            dlen (bit-and (second data) 127)
            mstart (if (== dlen 127) 10 (if (== dlen 126) 4 2))
            mask (drop 2 (take (+ mstart 4) data))
            msg (make-array Byte/TYPE (- (:size frame) (+ mstart 4)))]
       (loop [i (+ mstart 4), j 0]
          (aset-byte msg j (byte (bit-xor (nth data i) (nth mask (mod j 4)))))
          (if (< i (dec(:size frame))) (recur (inc i) (inc j))))
        msg))
    
    (defn ws-encode [data]
      "takes in bytes, return websocket frame"
      (let [len (count data)
            blen (if (> len 65535) 10 (if (> len 125) 4 2))
            buf (make-array Byte/TYPE (+ len blen))
            _ (aset-byte buf 0 -127) ;;(bit-or (unchecked-byte 0x80) 
                                               (unchecked-byte 0x1)
            _ (if (= 2 blen) 
                (aset-byte buf 1 len) ;;mask 0, len
                (do
                  (dorun(map #(aset-byte buf %1 
                          (unchecked-byte (bit-and (bit-shift-right len (*(- %2 2) 8))
                                                   255)))
                          (range 2 blen) (into ()(range 2 blen))))
                  (aset-byte buf 1 (if (> blen 4) 127 126))))
            _ (System/arraycopy data 0 buf blen len)]
        buf))
    
        11
  •  0
  •   pcunite    9 年前

    C++实现(不是我做的) here 。请注意,当您的字节数超过65535时,您需要使用长值进行移位,如图所示 here

        12
  •  0
  •   Sergey K    4 年前

    已更新 Haribabu Pasupathy 处理TCP分段的代码。在我的案例中,浏览器发送的大于1024字节的websocket数据包被拆分为TCP段,因此需要重新组装。

    private static void processResponse(InputStream inputStream, OutputStream outputStream) throws IOException {
        int readPacketLength = 0;
        byte[] packet = new byte[1024];
        ByteArrayOutputStream packetStream = new ByteArrayOutputStream();
    
        while(true) {
            readPacketLength = inputStream.read(packet);
    
            if(readPacketLength != -1) {
                if ((packet[0] & (byte) 15) == (byte) 8) { // Disconnect packet
                    outputStream.write(packet, 0, readPacketLength);
                    // returning the same packet for client to terminate connection
                    outputStream.flush();
                    return;
                }
                byte messageLengthByte = 0;
                int messageLength = 0;
                int maskIndex = 2;
                int messageStart = 0;
                //b[0] is always text in my case so no need to check;
                byte data = packet[1];
                byte op = (byte) 127; // 0111 111
                messageLengthByte = (byte) (data & op);
    
                int totalPacketLength = 0;
                if (messageLengthByte == (byte) 126 || messageLengthByte == (byte) 127) {
                    if (messageLengthByte == (byte) 126) {
                        maskIndex = 4;
                        // if (messageLengthInt==(byte)126), then 16-bit length is stored in packet[2] and [3]
                        ByteBuffer messageLength16Bit = ByteBuffer.allocateDirect(4);
                        messageLength16Bit.order(ByteOrder.BIG_ENDIAN);
                        messageLength16Bit.put((byte) 0x00);
                        messageLength16Bit.put((byte) 0x00);
                        messageLength16Bit.put(packet, 2, 2);
                        messageLength16Bit.flip();
                        messageLength = messageLength16Bit.getInt();
                        totalPacketLength = messageLength + 8;
                    } else {
                        maskIndex = 10;
                        // if (messageLengthInt==(byte)127), then 64-bit length is stored in bytes [2] to [9]. Using only 32-bit
                        ByteBuffer messageLength64Bit = ByteBuffer.allocateDirect(4);
                        messageLength64Bit.order(ByteOrder.BIG_ENDIAN);
                        messageLength64Bit.put(packet, 6, 4);
                        messageLength64Bit.flip();
                        messageLength = messageLength64Bit.getInt();
                        totalPacketLength = messageLength + 14;
                    }
    
                    if (readPacketLength != totalPacketLength) {
                        packetStream.write(packet, 0, readPacketLength);
    
                        int lastPacketLength = 0;
                        while (readPacketLength < totalPacketLength) {
                            packet = new byte[1024];
                            readPacketLength += lastPacketLength = inputStream.read(packet);
                            packetStream.write(packet, 0, lastPacketLength);
                        }
                        packet = packetStream.toByteArray();
                        packetStream.reset();
                    }
                }
                else { // using message length from packet[1]
                    messageLength = messageLengthByte;
                }
    
                byte[] masks = new byte[4];
                int i=0; int j=0;
                for(i = maskIndex; i < (maskIndex+4); i++) {
                    masks[j] = packet[i];
                    j++;
                }
    
                messageStart = maskIndex + 4;
    
                byte[] message = new byte[messageLength];
                for(i = messageStart, j = 0; i < readPacketLength; i++, j++){
                    message[j] = (byte) (packet[i] ^ masks[j % 4]);
                }
                System.out.println("Received message: " + new String(message));
                packet = new byte[1024];
            }
        }
    }
    
        13
  •  0
  •   Mika Notarnicola    4 年前

    我修复了>Nitij的C#实现中的65535消息长度问题。

    private static Byte[] EncodeMessageToSend(String message)
    {
        Byte[] response;
        Byte[] bytesRaw = Encoding.UTF8.GetBytes(message);
        Byte[] frame = new Byte[10];
    
        Int32 indexStartRawData = -1;
        Int32 length = bytesRaw.Length;
    
        frame[0] = (Byte)129;
        if (length <= 125)
        {
            frame[1] = (Byte)length;
            indexStartRawData = 2;
        }
        else if (length >= 126 && length <= 65535)
        {
            frame[1] = (Byte)126;
            frame[2] = (Byte)((length >> 8) & 255);
            frame[3] = (Byte)(length & 255);
            indexStartRawData = 4;
        }
        else
        {
            var lengthAsULong = Convert.ToUInt64(length);
            frame[1] = 127;
            frame[2] = (byte)((lengthAsULong >> 56) & 255);
            frame[3] = (byte)((lengthAsULong >> 48) & 255);
            frame[4] = (byte)((lengthAsULong >> 40) & 255);
            frame[5] = (byte)((lengthAsULong >> 32) & 255);
            frame[6] = (byte)((lengthAsULong >> 24) & 255);
            frame[7] = (byte)((lengthAsULong >> 16) & 255);
            frame[8] = (byte)((lengthAsULong >> 8) & 255);
            frame[9] = (byte)(lengthAsULong & 255);
    
            indexStartRawData = 10;
        }
    
        response = new Byte[indexStartRawData + length];
    
        Int32 i, reponseIdx = 0;
    
        //Add the frame bytes to the reponse
        for (i = 0; i < indexStartRawData; i++)
        {
            response[reponseIdx] = frame[i];
            reponseIdx++;
        }
    
        //Add the data bytes to the response
        for (i = 0; i < length; i++)
        {
            response[reponseIdx] = bytesRaw[i];
            reponseIdx++;
        }
    
        return response;
    }