@serhiops
Python/JavaScript/C++

Почему клиент WebSocket возвращает такие фреймы?

Мне нужно реализовать простой WebSocket сервер. Если фрагментация не используется на клиенте, данные доходят верно, но в обратном случае приходит много пакетов в том числе с неопределенными опкодами:

{ opcode: 1, length: 65522, last: 0 }
{ opcode: 7, length: 65472, last: 128 }
{ opcode: 0, length: 65522, last: 0 }
{ opcode: 3, length: 65530, last: 0 }
{ opcode: 14, length: 65530, last: 128 }
{ opcode: 3, length: 65530, last: 128 }
{ opcode: 15, length: 65530, last: 0 }
{ opcode: 2, length: 65530, last: 0 }
{ opcode: 7, length: 65530, last: 0 }
{ opcode: 10, length: 65530, last: 0 }
{ opcode: 1, length: 65530, last: 128 }
{ opcode: 12, length: 65530, last: 128 }
{ opcode: 15, length: 65530, last: 0 }
{ opcode: 2, length: 65530, last: 0 }
{ opcode: 0, length: 65530, last: 0 }
{ opcode: 13, length: 65530, last: 0 }
{ opcode: 15, length: 65530, last: 128 }
{ opcode: 2, length: 65530, last: 128 }
{ opcode: 0, length: 65528, last: 0 }
{ opcode: 13, length: 65530, last: 0 }
{ opcode: 12, length: 65528, last: 0 }
{ opcode: 1, length: 65530, last: 0 }
{ opcode: 1, length: 65530, last: 128 }
{ opcode: 12, length: 65530, last: 128 }
{ opcode: 12, length: 65530, last: 0 }
{ opcode: 1, length: 65530, last: 0 }
{ opcode: 4, length: 65530, last: 0 }
{ opcode: 9, length: 65530, last: 0 }
{ opcode: 3, length: 65530, last: 128 }
{ opcode: 14, length: 65530, last: 128 }
{ opcode: 13, length: 65530, last: 0 }
{ opcode: 0, length: 65530, last: 0 }
{ opcode: 0, length: 65530, last: 0 }
{ opcode: 13, length: 65530, last: 0 }
{ opcode: 11, length: 65530, last: 128 }
{ opcode: 6, length: 65530, last: 128 }
{ opcode: 14, length: 41016, last: 128 }

server:

'use strict';

const http = require('node:http');
const hash = require('./hash.js');
const handshake = require('./handshake.js');
const parser = require('./parser.js');

const buildAnswer = (message) => {
  const buffer = Buffer.alloc(message.length + 2);
  buffer[0] = 129;
  buffer[1] = message.length;
  Buffer.from(message).copy(buffer, 2, 0);
  return buffer;
};

const main = () => {
  const server = new http.Server();
  server.on('upgrade',  (request, socket) => {
    const { headers } = request;
    const { upgrade: protocol } = headers;
    if (protocol !== 'websocket') return;
    const clientKey = headers['sec-websocket-key'];
    const hashed = hash(clientKey);
    socket.write(handshake(hashed));
    socket.on('data', (chunk) => {
      const encoded = chunk.readInt8(1) & 128;
      // if (!encoded) return void socket.end();
      const opcode = chunk.readUInt8(0) & 15;
      const last = chunk.readUInt8(0) & 128;
      const mask = parser.getMask(chunk);
      const content = parser.getContent(chunk);
      const message = Uint8Array.from(content, (elt, i) => elt ^ mask[i % 4]);
      const string = String.fromCharCode(...message);
      console.log({ opcode, length: string.length, last });
      // console.log({ last, opcode  });
      const answer = buildAnswer('server');
      socket.write(answer);
    });
    socket.on('error', console.log);
  });
  server.listen(8000, '127.0.0.1');
};

main();

client:

'use strict';

const main = () => {
  const ws = new WebSocket('ws://127.0.0.1:8000');
  ws.onopen = () => {
    console.log('Connected');
    ws.send('client'.repeat(400000));
    ws.onmessage = (event) => {
      console.log(event.data);
    };
  };
  ws.onclose = () => console.log('Closed');
};

main();
  • Вопрос задан
  • 118 просмотров
Пригласить эксперта
Ответы на вопрос 1
VoidVolker
@VoidVolker
Dark side eye. А у нас печеньки! А у вас?
Возможно клиент использует дополнительные зарезервированные опкоды для каких-то своих целей/задач со своим сервером и поэтому он не соответствует стандарту. При условии, что фреймы получены правильно, конечно.
UPD: вероятно фреймы просто приходят кусками и вы не учитываете данный момент в своём коде. Спасибо Ivan Ustûžanin за напоминание данного факта.

RFC 6455 #5.2
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.

  • %x0 denotes a continuation frame
  • %x1 denotes a text frame
  • %x2 denotes a binary frame
  • %x3-7 are reserved for further non-control frames
  • %x8 denotes a connection close
  • %x9 denotes a ping
  • %xA denotes a pong
  • %xB-F are reserved for further control frames
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы