Примітка: Це деяке пояснення та псевдокод щодо того, як реалізувати дуже тривіальний сервер, який може обробляти вхідні та вихідні повідомлення 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
), або?