Javascript — клиент WebSocket не получает событие onmessage, когда сервер отправляет большой ответ

#javascript #.net #websocket

#javascript #.net #websocket

Вопрос:

Я создаю сервер .net websocket на основе TcpClient и NetworkStream, взаимодействующих с клиентом Javascript. После рукопожатия клиент запрашивает сервер для выполнения определенных действий, и сервер генерирует ответ — до сих пор это были короткие строки JSON, отправляемые обратно клиенту — и все работает нормально.

После того, как я получил требование отправлять более крупные строковые ответы (а именно, изображения в кодировке base64 с 200k и более байтами), клиент перестал получать ответы, и событие onmessage не запускается. Если я переключусь и отправлю короткий json — он снова работает нормально.

Когда я отправляю большие данные:

При отправке больших данных

Когда я отправляю простые данные:

При отправке простых данных

На стороне клиента я удалил код из всего, что не связано (поведение осталось прежним)

 try{
    ws = new WebSocket("ws://127.0.0.1:8282");
    ws.binaryType = "arraybuffer";
}
catch(err){
    debugger;
    document.getElementById("message").innerHTML = "Not Connected! "   err;         
};
ws.onopen = function () {
    var jsonRequest = '{"action" : "START_STREAM","timeout"  : 20}';
    ws.send("START_STREAM");
};
  

На стороне сервера я изолировал код после генерации ответа (обычная строка с изображением в кодировке base64, которое я протестировал и правильно декодировал):

  Byte[] frame = CreateFrameFromString(serverResponse);
 networkStream.Write(frame, 0, frame.Count());
 networkStream.Flush();
 clientSocket.Close();
 clientSocket = ServerListener.AcceptTcpClient();
 networkStream = clientSocket.GetStream();
  

Код для инициализации серверного потока:

  ServerListener.Start();
 clientSocket = ServerListener.AcceptTcpClient();
 NetworkStream networkStream = clientSocket.GetStream();
 while (true)
    {
     if (!networkStream.DataAvailable)
  ...regular loop/server stuff/handshake etc.
  

Ниже приведен метод CreateFrameFromString. Код операции проверяется со значениями 0-10, и во всех случаях поведение было одинаковым — ответ не был получен на стороне клиента.

  private static byte[] CreateFrameFromString(string message, Opcode opcode = Opcode.Text)
    {
        var payload = Encoding.UTF8.GetBytes(message);

        byte[] frame;

        if (payload.Length < 126)
        {
            frame = new byte[1 /*op code*/   1 /*payload length*/   payload.Length /*payload bytes*/];
            frame[1] = (byte)payload.Length;
            Array.Copy(payload, 0, frame, 2, payload.Length);
        }
        else if (payload.Length >= 126 amp;amp; payload.Length <= 65535)
        {
            frame = new byte[1 /*op code*/   1 /*payload length option*/   2 /*payload length*/   payload.Length /*payload bytes*/];
            frame[1] = 126;
            frame[2] = (byte)((payload.Length >> 8) amp; 255);
            frame[3] = (byte)(payload.Length amp; 255);
            Array.Copy(payload, 0, frame, 4, payload.Length);
        }
        else
        {
            frame = new byte[1 /*op code*/   1 /*payload length option*/   8 /*payload length*/   payload.Length /*payload bytes*/];
            frame[1] = 127; // <-- Indicates that payload length is in following 8 bytes.
            frame[2] = (byte)((payload.Length >> 56) amp; 255);
            frame[3] = (byte)((payload.Length >> 48) amp; 255);
            frame[4] = (byte)((payload.Length >> 40) amp; 255);
            frame[5] = (byte)((payload.Length >> 32) amp; 255);
            frame[6] = (byte)((payload.Length >> 24) amp; 255);
            frame[7] = (byte)((payload.Length >> 16) amp; 255);
            frame[8] = (byte)((payload.Length >> 8) amp; 255);
            frame[9] = (byte)(payload.Length amp; 255);
            Array.Copy(payload, 0, frame, 10, payload.Length);
        }

        frame[0] = (byte)((byte)opcode | 0x80 /*FIN bit*/);

        return frame;
    }
  

Я что-то упускаю — протокол / размер буфера / и т.д.? Во время тестирования я заметил, что могу отправить ответ до 4250 символов с вышеуказанной настройкой без каких-либо изменений. Как только я набрал это число, ответ начал исчезать.

Ответ №1:

После долгих поисков и устранения неполадок оказалось, что мне пришлось отправлять данные в пакетах, а не целиком. Я разделил ответ на куски (50000 символов) и отправил их 1 на 1, в то время как на стороне клиента я собирал фрагменты в событии onmessage. После того, как все фрагменты ответа были отправлены, я закрыл сеанс, который на стороне клиента вызвал создание образа из потока base64.