WebSocket закрывается с ошибкой протокола 1002

Я реализую клиент командной строки сообщений WebSocket. Я проверил, что эта ошибка соответствует проблеме с протоколом. Я обновил ws до новейшей версии 7.4.1. В бэкэнде я использую Spring Boot Websockets версии 2.3.4.RELEASE.

Говорят, что две основные причины этого - потеря пакетов или искаженные сообщения. Я сделал несколько проверок, чтобы проверить их, но ни один из них не кажется действительным. Сообщения, которые я тестирую, небольшие, поэтому размер сообщения не должен быть таким. Соединение полностью на локальном хосте. Я тестирую решение с 3 пользователями, и иногда я получаю эту ошибку, иногда нет.

Может ли кто-нибудь помочь мне понять, как избавиться от этого типа ошибки?

Вот код, который я использую для отправки сообщений клиентом:

async function test(number_of_messages, break_between_messages) {
const websocket = new WebSocket(url...)

websocket.on('message', function incoming(data) {
    console.info(getMessage("Received", data))
});

websocket.on('close', function(data) {
    console.info('Disconnected!!!! ' + data.toString());
});

const opened = await connection(websocket)

//Wait 5 seconds
await sleep(5_000);

if (opened) {
    for (i = 0; i < number_of_messages; i++) {

        for (const chatId of chatIds) {
            let content = i.toString() + " from " + user;
            let msg = JSON.stringify({
                "chatId": chatId,
                "author": user,
                "content": content
            })
            websocket.send(msg)

            let message = getMessage("Sent", msg)
            console.info(message)
        }

        await sleep(break_between_messages);
    }

} else {
    console.info("ERROR on Opening Connection")
    return
}

// Wait 1 minute
await sleep(60_000);
websocket.close()

}

С внутренним кодом:

@Component
@ServerEndpoint(value = "/webSocket/{username}",
        encoders = MessageRepresentationEncoder.class, decoders = MessageRepresentationDecoder.class)
public class MessagingSocket {
    private Logger logger = LoggerFactory.getInstance();
    private Session session;
    private MessagingAPI messagingAPI = MessagingAPIFactory.createAPI();
    private UserSocketRegistry userSocketRegistry = UserSocketRegistry.createRegistry();
    private SessionUserRegistry sessionUserRegistry = SessionUserRegistry.createRegistry();

    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username) {
        this.session = session;
        logger.log(LoggingType.INFO, "Started new session " + session.getId());
        logger.log(LoggingType.INFO, username + " connected");

        userSocketRegistry.addSessionForUser(this, username);
        sessionUserRegistry.addSessionForUser(session, username);
    }

    @OnMessage //Allows the client to send message to the socket.
    public void onMessage(MessageRepresentation messageRepresentation) {
        logger.log(LoggingType.INFO, "Received " + messageRepresentation.toString());
        messagingAPI.write(WriteMessage.from(UUID.fromString(messageRepresentation.chatId), messageRepresentation.author, messageRepresentation.content));
        broadcastToChat(messageRepresentation);
    }

    private void broadcastToChat(MessageRepresentation message) {
        final List<MessagingSocket> sockets = messagingAPI.getUsersConnectedToChat(UUID.fromString(message.chatId)).stream().filter(user -> userSocketRegistry.hasSocketFor(user.getName()))
                .map(user -> userSocketRegistry.getSocketFor(user.getName())).collect(Collectors.toList());

        logger.log(LoggingType.INFO, "Starting broadcast of " + message.content + " from " + message.author + " for " + String.join(",", messagingAPI.getUsersConnectedToChat(UUID.fromString(message.chatId)).stream().map(x -> x.getName()).collect(Collectors.toList())));
        for (MessagingSocket messagingSocket : sockets) {
            logger.log(LoggingType.INFO, "Broadcasting message" + message.content + " to " + messagingSocket.session.getId());
            messagingSocket.sendMessage(message);

        }
    }

    private void sendMessage(MessageRepresentation message) {
        try {
            this.session.getBasicRemote().sendObject(message);
        } catch (IOException | EncodeException e) {
            logger.log(LoggingType.ERROR, "Caught exception while sending message to Session Id: " + this.session.getId());
        }
    }

    @OnClose
    public void onClose(Session session) {
        String user = sessionUserRegistry.getUserFor(session);
        logger.log(LoggingType.INFO, "User " + user + " with session " + this.session.getId() + " disconnected ");
        sessionUserRegistry.removeSession(session);
        userSocketRegistry.removeUser(user);
    }
}

И представление сообщения как:

public class MessageRepresentation {
    public String chatId;
    public String author;
    public String content;

    @Override
    public String toString() {
        return "MessageRepresentation{" +
                "chatId='" + chatId + '\'' +
                ", author='" + author + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

После дальнейшего расследования я получаю следующее исключение:

java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.checkState(WsRemoteEndpointImplBase.java:1243)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.textStart(WsRemoteEndpointImplBase.java:1205)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendString(WsRemoteEndpointImplBase.java:191)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendObject(WsRemoteEndpointImplBase.java:600)
at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendObject(WsRemoteEndpointBasic.java:74)
at presentation.frontend.websockets.server.MessagingSocket.sendMessage(MessagingSocket.java:64)
at presentation.frontend.websockets.server.MessagingSocket.broadcastToChat(MessagingSocket.java:57)
at presentation.frontend.websockets.server.MessagingSocket.onMessage(MessagingSocket.java:47)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBase.onMessage(PojoMessageHandlerWholeBase.java:80)
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:402)
at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:119)
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:502)
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:301)
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:82)
at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:171)
at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148)
at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:59)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)

java.lang.IllegalStateException: сообщение не будет отправлено, поскольку сеанс WebSocket закрыт

пожалуйста, поделитесь кодом, связанным с бэкэнд-веб-сокетом

Chandan 15.12.2020 18:43

Я включил код конечной точки

Hyphen 18.12.2020 21:18

Является ли _ в awaits частью синтаксиса? Я не думаю, что когда-либо видел это. Не то, чтобы это должно было вызывать ошибку, которую вы имеете. Не могли бы вы также обобщить, что вы делаете для репликации, и, возможно, какая строка является последней строкой работающего кода перед тем, как выдается ошибка?

Shmack 21.12.2020 00:51

Не могли бы вы указать точную строку с комментарием awaits, если я правильно понимаю, это то же самое использование, что и здесь v8.dev/features/numeric-separators? Я запускаю сервер и перезапускаю остальные, как показано здесь, затем после нескольких сообщений я вижу журнал, который находится в разделе onClose клиента. Это происходит примерно в 70% случаев в среднем с одним из агентов. Я использую 3 агента для своих тестов.

Hyphen 21.12.2020 01:14

Вероятно, вам следовало пометить фреймворк, который вы используете, чтобы привлечь больше просмотров, относящихся к вашему вопросу.

John 21.12.2020 01:42
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
5
8 842
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я мог бы ошибиться, но я думаю, что это, вероятно, связано с сообщением, содержащим недопустимую кодировку UTF8 или что-то в этом роде. то есть деформированный.

Если это звучит так, как будто это может быть причиной, простое исправление будет состоять в том, чтобы закодировать msg

        let msg = JSON.stringify({
            "chatId": chatId,
            "author": user,
            "content": content
        })

к

  let msg = unescape(encodeURIComponent(JSON.stringify({
                "chatId": chatId,
                "author": user,
                "content": content
            })));

Затем расшифруйте с другой стороны...

JSON.parse(decodeURIComponent(escape( ... )))

Похоже, я все еще отключаю некоторых клиентов (вот часть журнала для Агента 1): [1608576813254]Получено: {"chatId":"0ea9c68c-fe9a-4bc6-adc9-0068cab1b013","author":"A‌​gent3 ","content":"18 от Agent3"} Отключено!!!! 1002

Hyphen 21.12.2020 19:55

Поскольку ваш ответ может быть важным, я собираюсь дать вам награду. Я собираюсь проверить в Wireshark, почему сообщение было искажено.

Hyphen 21.12.2020 20:34

Я заглянул в Wireshark во время выполнения этого теста: я вижу закрытие соединения WebSocket [FIN], и когда я смотрю данные, отображается «Произошло неисправимое исключение IOException, поэтому соединение было закрыто»; это сообщение отправляется с моего сервера клиенту

Hyphen 22.12.2020 15:21
Ответ принят как подходящий

Решение этого вопроса включало 2 шага.

1: Найдите трассировку стека ошибки

@OnError
public void onError(Session session, Throwable throwable) {
    logger.log(LoggingType.ERROR, "Error for " + session.getId() + " caused by: " + throwable.getMessage());
    throwable.printStackTrace();
}

2: Изменить синхронный BasicRemote на асинхронный AsyncRemote в широковещательных сообщениях (это важно при увеличении количества сообщений)

private void sendMessage(MessageRepresentation message) {
        this.session.getAsyncRemote().sendObject(message);
    }

Другие вопросы по теме