Як я можу надсилати та отримувати повідомлення WebSocket на стороні сервера?


85
  • Як я можу надсилати та отримувати повідомлення на стороні сервера за допомогою WebSocket, згідно з протоколом?

  • Чому я отримую, здавалося б, випадкові байти на сервері, коли надсилаю дані з браузера на сервер? Це дані закодовані якось?

  • Як працює кадрування в обох напрямках: сервер → клієнт і клієнт → сервер?

Відповіді:


154

Примітка: Це деяке пояснення та псевдокод щодо того, як реалізувати дуже тривіальний сервер, який може обробляти вхідні та вихідні повідомлення WebSocket відповідно до остаточного формату кадрування. Він не включає процес рукостискання. Крім того, ця відповідь була зроблена в освітніх цілях; це не повнофункціональна реалізація.

Специфікація (RFC 6455)


Надсилання повідомлень

(Іншими словами, сервер → браузер)

Фрейми, які ви надсилаєте, повинні бути відформатовані відповідно до формату обрамлення WebSocket. Для надсилання повідомлень такий формат:

  • один байт, що містить тип даних (і деяку додаткову інформацію, яка виходить за межі тривіального сервера)
  • один байт, який містить довжину
  • або два, або вісім байтів, якщо довжина не входить у другий байт (другий байт - це тоді код, який говорить, скільки байтів використовується для довжини)
  • фактичні (необроблені) дані

Перший байт буде 1000 0001(або 129) для текстового кадру.

Для другого байта встановлено перший біт, 0оскільки ми не кодуємо дані (кодування від сервера до клієнта не є обов’язковим).

Необхідно визначити довжину вихідних даних, щоб правильно відправити байти довжини:

  • якщо 0 <= length <= 125вам не потрібні додаткові байти
  • якщо 126 <= length <= 65535вам потрібні два додаткові байти, а другий байт -126
  • якщо length >= 65536вам потрібні вісім додаткових байтів, а другий байт -127

Довжину потрібно нарізати на окремі байти, а це означає, що вам потрібно буде зсунути біт вправо (із сумою у вісім бітів), а потім зберегти лише останні вісім бітів, виконавши 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

Чому 1000 0001(129) для текстового кадру? Специфікація каже каже: %x1 denotes a text frame. Так має бути 0000 0001( 0x01), або?
Денніс,

3
@Dennis: Операційний код кадру - це 0001, як зазначено в заголовку тієї частини специфікації: "Opcode: 4 біти". Перший байт складається з FIN, RSV1-3 та коду операції. Плавець 1, RSV1-3 все три 0і опкод це , 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

На жаль, це не працює. Я просто скопіював недійсну трансляцію (із сервера на клієнта) у свою програму. Сокет успішно підключено, повідомлення успішно надіслано браузеру, але браузер нічого не отримав.
nick

18

Впровадження 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;
}

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[де "тест" - це моє повідомлення. З чого походить інша частина?
Snickbrack

1
Вибачте за пізній відповідь. Я створив невелику програму C # (консоль та веб), щоб спробувати веб-сокети. Ви можете завантажити їх звідси, щоб побачити, як вони закодовані. Посилання: dropbox.com/s/gw8hjsov1u6f7c0/Web%20Sockets.rar?dl=0
Нітій

Для мене це не вдалося у великих повідомленнях. Я замінив код довжини> 65535 на: var l = Convert.ToUInt64 (довжина); var b = BitConverter.GetBytes (l); Array.Reverse (b, 0, b.Length); b.CopyTo (кадр, 2); ... який, здається, виправив речі.
Шон

Хороша робота. Тільки одне: у DecodeMessage я обчислюю "декодовану" довжину масиву на основі даних про довжину корисного навантаження, які включені до кадру даних, оскільки довжина масиву "байт" не може бути точною. довжина масиву "bytes" залежить від способу читання потоку.
user1011138

@Sean, ти можеш показати мені свій повний приклад виправлення проблеми з великими повідомленнями? я не можу змінити цей код на зразок.
Алі Юсефі

6

Відповідь 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', '!']

Я намагався використати ваш код у своєму сценарії, але безуспішно. Чи не могли б ви допомогти? stackoverflow.com/questions/43748377/…
Як

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

Дякую за відповідь, я хотів би додати до версії Python hfern (вище), щоб включити функцію надсилання, якщо хтось зацікавлений.

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, вам потрібно зсунути довге значення, як показано тут .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.