서버 측에서 WebSocket 메시지를 어떻게 보내고받을 수 있습니까?


85
  • 프로토콜에 따라 WebSocket을 사용하여 서버 측에서 메시지를 어떻게 보내고받을 수 있습니까?

  • 브라우저에서 서버로 데이터를 보낼 때 서버에서 임의의 바이트를받는 이유는 무엇입니까? 어떻게 든 인코딩 된 데이터입니까?

  • 프레이밍은 서버 → 클라이언트 및 클라이언트 → 서버 방향 모두에서 어떻게 작동합니까?

답변:


154

참고 : 이것은 최종 프레임 형식에 따라 수신 및 발신 WebSocket 메시지를 처리 ​​할 수있는 매우 간단한 서버를 구현하는 방법에 대한 설명 및 의사 코드입니다. 핸드 셰이 킹 프로세스는 포함되지 않습니다. 또한이 답변은 교육 목적으로 작성되었습니다. 완전한 기능을 갖춘 구현이 아닙니다.

사양 (RFC 6455)


메시지 보내기

(즉, 서버 → 브라우저)

보내는 프레임은 WebSocket 프레임 형식에 따라 형식을 지정해야합니다. 메시지를 보내는 경우이 형식은 다음과 같습니다.

  • 데이터 유형 (및 사소한 서버의 범위를 벗어난 일부 추가 정보)을 포함하는 1 바이트
  • 길이를 포함하는 1 바이트
  • 길이가 두 번째 바이트에 맞지 않으면 2 바이트 또는 8 바이트 (두 번째 바이트는 길이에 사용되는 바이트 수를 나타내는 코드입니다)
  • 실제 (원시) 데이터

첫 번째 바이트는 텍스트 프레임의 경우 1000 0001(또는 129)입니다.

두 번째 바이트는 0데이터를 인코딩하지 않기 때문에 첫 번째 비트가로 설정됩니다 (서버에서 클라이언트로 인코딩하는 것은 필수가 아님).

길이 바이트를 올바르게 전송하려면 원시 데이터의 길이를 결정해야합니다.

  • 인 경우 0 <= length <= 125추가 바이트가 필요하지 않습니다.
  • 이면 126 <= length <= 65535두 개의 추가 바이트가 필요하고 두 번째 바이트는126
  • 이면 length >= 655368 바이트가 추가로 필요하고 두 번째 바이트는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)

메시지 받기

(즉, 브라우저 → 서버)

획득 한 프레임은 다음 형식입니다.

  • 데이터 유형을 포함하는 1 바이트
  • 길이를 포함하는 1 바이트
  • 길이가 두 번째 바이트에 맞지 않는 경우 2 바이트 또는 8 바이트 추가
  • 마스크 인 4 바이트 (= 디코딩 키)
  • 실제 데이터

첫 번째 바이트는 일반적으로 중요하지 않습니다. 텍스트를 보내는 경우에만 텍스트 유형을 사용하는 것입니다. 이 경우 1000 0001(또는 129)이됩니다.

두 번째 바이트와 추가 2 또는 8 바이트는 길이에 사용되는 바이트 수를 알아야하기 때문에 약간의 구문 분석이 필요합니다 (실제 데이터가 시작되는 위치를 알아야 함). 데이터가 이미 있으므로 길이 자체는 일반적으로 필요하지 않습니다.

두 번째 바이트의 첫 번째 비트는 항상 1데이터가 마스킹 (= 인코딩 됨)됨을 의미합니다. 클라이언트에서 서버로 보내는 메시지는 항상 마스킹됩니다. 을 수행하여 첫 번째 비트를 제거해야합니다 secondByte AND 0111 1111. 결과 바이트가 두 번째 바이트에 맞지 않아 길이를 나타내지 않는 두 가지 경우가 있습니다.

  • 0111 1110또는 의 두 번째 바이트 126는 다음 두 바이트가 길이로 사용됨을 의미합니다.
  • 0111 1111또는 의 두 번째 바이트 127는 다음 8 바이트가 길이로 사용됨을 의미합니다.

4 개의 마스크 바이트는 전송 된 실제 데이터를 디코딩하는 데 사용됩니다. 디코딩 알고리즘은 다음과 같습니다.

decodedByte = encodedByte XOR masks[encodedByteIndex MOD 4]

여기서 encodedByte데이터의 원본 바이트이고, encodedByteIndex첫 번째 바이트로부터의 바이트 카운트의 지수 (오프셋)는 실제 데이터의 인덱스를 가지고 0. masks4 개의 마스크 바이트를 포함하는 배열입니다.

이로 인해 디코딩을 위해 다음과 같은 의사 코드가 생성됩니다.

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

1000 0001텍스트 프레임에 (129)? 사양에 따르면 %x1 denotes a text frame. 따라서 0000 0001( 0x01) 또는?
Dennis

3
@Dennis : 프레임 opcode는 0001"Opcode : 4 bits"사양의 해당 부분 헤더에 명시되어 있습니다. 첫 번째 바이트는 FIN, RSV1-3 및 opcode로 구성됩니다. FIN은 1RSV1-3 모든 세이며, 0상기 op 코드는 0001에 가산하는 1000 0001제 바이트. 또한 다른 부분에서 바이트가 분할되는 방식을 보여주는 사양의 삽화를 참조하십시오.
pimvdb

서버-> 클라이언트 모델에 'bytesFormatted [2] = (bytesRaw.length >> 56) AND 255'와 같은 몇 줄이 있습니다. 그리고 나에게 논리 연산자 인 것 같아서 단순히 숫자를 입력하면 C #에서 나를 위해 무엇이든 할 것이라고 기대할 수 없습니다. 마찬가지로, 마크 업의 ">>"가 무엇을 나타내야하는지 잘 모르겠습니다.하지만 C #으로 전송됩니다 ... 그것이 나에게 의미하는 바가 무엇이든 ... : P
DigitalJedi805

누구든지 나를 위해 실제로 이것을 해결할 수 있다면 C # 구현을 답변으로 게시하게되어 기쁩니다.
DigitalJedi805

1
@Neevek : 그들이 의미하는 것은 마스크 바이트 자체가 예측할 수 없어야한다는 것입니다. 그들이 일정하다면 그다지 중요하지 않습니다. 기본적으로 악의적 인 사용자가 데이터 조각을 가지고있는 경우 마스크 없이는이를 디코딩 할 수 없습니다. 마스크의 경우 위치는 다음 예측할 수없는 그것은 :) 디코드에 정품 서버에 대한 조금 어렵습니다
pimvdb

26

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
읽기 작업에 적합한 버퍼 길이는 얼마입니까?
jackgerrits 2015

불행히도 작동하지 않습니다. 방금 무효 방송 (서버에서 클라이언트로)을 내 프로그램에 복사했습니다. 소켓이 성공적으로 연결되었고 메시지가 브라우저에 성공적으로 전송되었지만 브라우저에서 아무것도받지 못했습니다.
nick

18

자바 스크립트 구현 :

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;
}

5
JavaScript가 실제로 2^31 - 1.
pimvdb

13

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;
    }

1
디코드 기능은 항상 test�c=ܝX["test"가 내 메시지 인 여기와 같이 정의되지 않은 부록과 함께 내 특정 메시지를 반환 합니다. 다른 부분은 무엇입니까?
Snickbrack

1
늦은 답변 죄송합니다. 웹 소켓을 사용해보기 위해 작은 C # 애플리케이션 (콘솔 및 웹)을 만들었습니다. 여기에서 다운로드하여 어떻게 코딩되는지 확인할 수 있습니다. 링크 : dropbox.com/s/gw8hjsov1u6f7c0/Web%20Sockets.rar?dl=0
Nitij

이것은 큰 메시지에서 나를 위해 실패했습니다. 길이> 65535 코드를 다음으로 대체했습니다. var l = Convert.ToUInt64 (length); var b = BitConverter.GetBytes (l); Array.Reverse (b, 0, b.Length); b. CopyTo (프레임, 2); ... 고정 된 것 같습니다.
Sean

잘 했어. 단 한 가지 : DecodeMessage에서 "바이트"배열 길이가 정확할 수 없기 때문에 데이터 프레임에 포함 된 페이로드 길이 데이터를 기반으로 "디코딩 된"배열 길이를 계산합니다. "바이트"배열 길이는 스트림을 읽는 방식에 따라 다릅니다.
user1011138

@Sean 큰 메시지 문제 해결에 대한 전체 예제를 보여줄 수 있습니까? 해당 코드를 샘플로 변경할 수 없습니다.
알리 Yousefi

6

pimvdb의 답변은 파이썬으로 구현되었습니다.

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', '!']

내 스크립트에서 코드를 사용하려고했지만 성공하지 못했습니다. 도움이 될 수 있습니까? stackoverflow.com/questions/43748377/…
yak

5

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 클래스에서이 기능과 기타 기능을 구현했습니다 .


4

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;
}

4

답변 해 주셔서 감사합니다 . 관심이 있으시면 Sending 기능을 포함하도록 hfern의 (위) Python 버전에 추가하고 싶습니다 .

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")

2

Go에서 구현

인코딩 부분 (서버-> 브라우저)

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)
}

2

Clojure, 디코드 기능은 프레임이 맵으로 전송된다고 가정합니다. {: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))

0

C ++ 구현 (안 내게로) 여기 . 바이트가 65535를 초과하면 여기에 표시된대로 긴 값으로 이동해야합니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.