Websocket: отправка сообщений через 65535 байт не выполняется

Я разработал сервер websocket в Java с нуля. Клиент javascript работает в браузере:

function connectToServer() {
    connection = new WebSocket("ws://" + document.domain + ":8351");       
    connection.onopen = function () {
    };

    connection.onmessage = function (e) {
        handleServerResponse(e.data);
    };
}

Все нормально, пока сообщения (json) не достигнут 65535 байт. Затем сокет закрывается (я не понял, если клиент или сервер закрывает соединение.

В консоли браузера (попробовал несколько браузеров) я вижу: Соединение с ws://localhost: 8351/было прервано во время загрузки страницы.

На стороне сервера я вижу: java.net.SocketException: Connection reset  на java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)

Итак, если проблема в рукопожатии или я неправильно создаю фрейм на сервере, а клиент закрывает соединение, или я пишу байты в поток неправильно, а java io закрывает сокет.

Мой код (сервер):

1) Рукопожатие (ответ сервера)

  String _01 = "HTTP/1.1 101 Switching Protocols\r\n";
  String _02 = "Upgrade: websocket\r\n";
  String _03 = "Connection: Upgrade\r\n";
  String _04 = "Sec-WebSocket-Accept: " + responseKey + "\r\n";
  String _05 = "Content-Encoding: identity\r\n";

2) Построение кадра (если большие сообщения будут разбиты на разные кадры?)

public static byte[] buildFrame(String message)
{
    int length = message.length();
    int rawDataIndex = -1;
    if (length <= 125)
        rawDataIndex = 2;
    else if (length >= 126 && length <= 65535)
        rawDataIndex = 4;
    else
        rawDataIndex = 10;
    byte[] frame = new byte[length + rawDataIndex];
    frame[0] = (byte)129;
    if (rawDataIndex == 2)
        frame[1] = (byte)length;
    else if (rawDataIndex == 4)
    {
        frame[1] = (byte)126;
        frame[2] = (byte)(( length >> 8 ) & (byte)255);
        frame[3] = (byte)(( length      ) & (byte)255);
    }
    else
    {
        frame[1] = (byte)127;
        frame[2] = (byte)(( length >> 56 ) & (byte)255);
        frame[3] = (byte)(( length >> 48 ) & (byte)255);
        frame[4] = (byte)(( length >> 40 ) & (byte)255);
        frame[5] = (byte)(( length >> 32 ) & (byte)255);
        frame[6] = (byte)(( length >> 24 ) & (byte)255);
        frame[7] = (byte)(( length >> 16 ) & (byte)255);
        frame[8] = (byte)(( length >>  8 ) & (byte)255);
        frame[9] = (byte)(( length       ) & (byte)255);

    }
    for (int i = 0; i < length; i++)
        frame[rawDataIndex + i] = (byte)message.charAt(i);
    return frame;
}

3) Запись байтов в сокет (я пробовал socket.setSendBufferSize и BufferedOutputStream, ничего не помогает)

socket.getOutputStream().write(byteMessage);
socket.getOutputStream().flush();

Кто-нибудь сталкивался с той же проблемой? Любая помощь приветствуется!

Ответ 1

Я знаю, что это немного поздно для ответа... но в любом случае, я столкнулся с той же проблемой и этим кодом:

    frame[1] = (byte)127;
    frame[2] = (byte)(( length >> 56 ) & (byte)255);
    frame[3] = (byte)(( length >> 48 ) & (byte)255);
    frame[4] = (byte)(( length >> 40 ) & (byte)255);
    frame[5] = (byte)(( length >> 32 ) & (byte)255);
    frame[6] = (byte)(( length >> 24 ) & (byte)255);
    frame[7] = (byte)(( length >> 16 ) & (byte)255);
    frame[8] = (byte)(( length >>  8 ) & (byte)255);
    frame[9] = (byte)(( length       ) & (byte)255);

работает. Ваша проблема здесь в том, что ваша переменная "длина" - это int, которая равна 32 бит. И вы выполняете смещение битов на 8 байтов, чтобы получить случайные данные из памяти. Если вы определите свою длину переменной длиной до 64 бит, то она будет работать.

long length = (long)message.length();

отлично работал у меня.

Я надеюсь, что это поможет кому-то, кто хочет понять.

Ответ 2

Как я и предполагал, код смены битов, населенный через Интернет, не работает.

Нашел следующий код (источник):

 frame[1] = (byte)127;

            int left = length;
            int unit = 256;

            for (int i = 9; i > 1; i--)
            {
                frame[i] = (byte)(left % unit);
                left = left / unit;

                if (left == 0)
                    break;
            }

И это работает! Хотя я не мог понять, какая разница.