Zdalny punkt końcowy WebSocket był w stanie [TEXT_PARTIAL_WRITING]


Używam tomcat 8.0.15, wiosna 4.1.5.
Zaimplementowałem 3 wymagane funkcje do korzystania z WebSocket, jak pokazano poniżej.
Wszystko jest bardzo proste.
private Map<String, WebSocketSession> map_users = new ConcurrentHashMap<>();
private Map<String, String> map_id = new ConcurrentHashMap<>();public void afterConnectionEstablished(WebSocketSession wss) throws Exception {
map_users.put(wss.getId(), wss);
}public void afterConnectionClosed(WebSocketSession wss, CloseStatus cs) throws Exception {
map_users.remove(wss.getId());// remove user
String username = map_id.get(wss.getId());
if (username != null) {
map_id.remove(wss.getId());
map_id.remove(username);
}
}public void handleTextMessage(WebSocketSession wss, TextMessage tm) throws Exception {
String str = tm.getPayload();
String username = ...;// regist user
if (!map_id.get(wss.getId())) {
map_id.put(wss.getId(), username);
map_id.put(username, wss.getId());
} for (WebSocketSession w: map_users.values()) {
w.sendMessage(new TextMessage(wss.getId() + " send to " + w.getId() + ", msg:" + tm.getPayload()));
}
}

Jeden klient wysyła wiadomość, a inni klienci otrzymują wiadomość za pośrednictwem handleTextMessage.
W moim przypadku bez funkcji handleTextMessage program serwera chce wysłać wiadomość tekstową do klientów.
(W tym celu zapisałem identyfikator WebSocketSession i nazwę użytkownika w map_id)
String websocketsesssion_id = map_id.get(username);
WebSocketSession wss = map_users.get(websocketsesssion_id);
wss.sendMessage(new TextMessage(new java.util.Date()));

Powyższy kod działa bardzo dobrze.
Ale kiedy jakiś klient WebSocketSession jest używany i próbuje użyć w tym samym czasie, popełnia błąd.
To znaczy
1. jakiś klient wysyła wiadomość - & > nazwa handleTextMessage - & > klient WebSocketSession używa
2. program serwera chce wysłać wiadomość do tego klienta - & > pobierz WebSocketSession klienta z karty - & > spróbuj wysłać wiadomość przy użyciu tej samej sesji WebSocketSession
Stacktrace:] with root cause
java.lang.IllegalStateException: The remote endpoint was in state [TEXT_PARTIAL_WRITING] which is an invalid state for called method
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.checkState(WsRemoteEndpointImplBase.java:1092)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.textPartialStart(WsRemoteEndpointImplBase.java:1050)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendPartialString(WsRemoteEndpointImplBase.java:218)
at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendText(WsRemoteEndpointBasic.java:49)
at org.springframework.web.socket.adapter.standard.StandardWebSocketSession.sendTextMessage(StandardWebSocketSession.java:197)
at org.springframework.web.socket.adapter.AbstractWebSocketSession.sendMessage(AbstractWebSocketSession.java:105)
at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.writeFrameInternal(WebSocketServerSockJsSession.java:222)
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.writeFrame(AbstractSockJsSession.java:325)
at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.sendMessageInternal(WebSocketServerSockJsSession.java:212)
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.sendMessage(AbstractSockJsSession.java:161)

W rezultacie sesja WebSocketSession zostaje zamknięta, a klient musi ponownie otworzyć nową sesję WebSocketSession.
Więc moje pytanie brzmi:
Czy mogę sprawdzić, czy usługa WebSocketSession jest używana, czy nie?
(poza funkcją handleTextMessage)
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Problem polega na tym, że wiele wątków próbuje pisać w tym samym czasie w gnieździe, więc:
próbka:
String websocketsesssion_id = map_id.get(username);
WebSocketSession wss = map_users.get(websocketsesssion_id);
synchronized(wss) {
wss.sendMessage(new TextMessage(new java.util.Date()));
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Podczas gdy synchronizacja wywołań
sendMessage ()
pomaga w przypadku połączenia ws://, nie pomaga w przypadku
wss://, tj. Połączenie SSL/TLS
. Jest to 100% niepowodzenie, jeśli próbujesz wysłać częściowe wiadomości podczas czytania częściowych wiadomości. Przetestowałem to na Spring Boot 1.4.2 RELEASE (tomcat 8.5.6)
To samo z Tomcat 8.5.9. Zobacz stos śledzenia poniżej.
[pool-18-thread-1] [GenericMessageEndpoint] Sending message to the endpoint: 
[pool-18-thread-2] [GenericMessageEndpoint] Sending message to the endpoint:
[pool-18-thread-3] [GenericMessageEndpoint] Sending message to the endpoint: [https-jsse-nio-8443-exec-1] [FrontendWebSocketHandler] Message from 0, isLast: false, length: 16384
[https-jsse-nio-8443-exec-1] [FrontendWebSocketHandler] Message from 0, isLast: false, length: 16384[pool-18-thread-3] [FrontendWebSocketHandler] Transport error. Session: StandardWebSocketSession[id=0, uri=/myt/websocket]
java.io.IOException: java.io.IOException: Unable to wrap data, invalid status [CLOSED]
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:315)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:258)
at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:606)
at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:494)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:313)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:250)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendPartialString(WsRemoteEndpointImplBase.java:223)
at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendText(WsRemoteEndpointBasic.java:49)
at org.springframework.web.socket.adapter.standard.StandardWebSocketSession.sendTextMessage(StandardWebSocketSession.java:197)
at org.springframework.web.socket.adapter.AbstractWebSocketSession.sendMessage(AbstractWebSocketSession.java:104)
at com.ebs.mytreasury.frontend.websocket.FrontendWebSocketHandler.send(FrontendWebSocketHandler.java:180)
at com.ebs.mytreasury.frontend.websocket.FrontendWebSocketHandler.send(FrontendWebSocketHandler.java:24)
at com.ebs.mytreasury.frontend.GenericMessageEndpoint.sendMessage(GenericMessageEndpoint.java:72)
at com.ebs.mytreasury.frontend.GenericMessageEndpoint.send(GenericMessageEndpoint.java:57)
at com.mytreasury.services.backend.MessageSender.process(MessageSender.java:24)
at com.mytreasury.services.backend.AbstractTopicMessageHandler.handle(AbstractTopicMessageHandler.java:47)
at com.mytreasury.services.backend.AbstractTopicMessageHandler.handle(AbstractTopicMessageHandler.java:52)
at com.mytreasury.services.backend.AbstractTopicMessageHandler.handle(AbstractTopicMessageHandler.java:52)
at com.mytreasury.services.backend.AbstractTopicMessageHandler.handle(AbstractTopicMessageHandler.java:52)
at com.mytreasury.services.backend.AbstractTopicMessageHandler.handle(AbstractTopicMessageHandler.java:52)
at com.mytreasury.services.backend.AbstractTopicMessageHandler.handle(AbstractTopicMessageHandler.java:52)
at com.mytreasury.services.backend.AbstractTopicMessageHandler.handle(AbstractTopicMessageHandler.java:52)
at com.mytreasury.services.backend.AbstractTopicMessageHandler.handle(AbstractTopicMessageHandler.java:52)
at com.mytreasury.services.backend.AbstractTopicMessageHandler.handle(AbstractTopicMessageHandler.java:52)
at com.ebs.mytreasury.frontend.message.handler.ResponseGenericMessageHandler.handle(ResponseGenericMessageHandler.java:52)
at com.ebs.mytreasury.frontend.socket.EventPublisherSocketHandler.handle(EventPublisherSocketHandler.java:96)
at com.ebs.mytreasury.frontend.socket.EventPublisherSocketHandler$1$1.run(EventPublisherSocketHandler.java:135)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: Unable to wrap data, invalid status [CLOSED]
at org.apache.tomcat.util.net.SecureNioChannel.write(SecureNioChannel.java:647)
at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101)
at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:157)
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1241)
at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:670)
at org.apache.tomcat.util.net.SocketWrapperBase.flushBlocking(SocketWrapperBase.java:607)
at org.apache.tomcat.util.net.SocketWrapperBase.flush(SocketWrapperBase.java:597)
at org.apache.tomcat.websocket.server.WsRemoteEndpointImplServer.doWrite(WsRemoteEndpointImplServer.java:95)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.writeMessagePart(WsRemoteEndpointImplBase.java:494)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:309)
... 29 common frames omitted
[https-jsse-nio-8443-exec-3] [FrontendWebSocketHandler] Transport error. Session: StandardWebSocketSession[id=0, uri=/myt/websocket]
javax.net.ssl.SSLException: bad record MAC
at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728)
at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:981)
at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:907)
at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
at org.apache.tomcat.util.net.SecureNioChannel.read(SecureNioChannel.java:563)
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1222)
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1195)
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1168)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:62)
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:53)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:789)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1437)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.crypto.BadPaddingException: bad record MAC
at sun.security.ssl.EngineInputRecord.decrypt(EngineInputRecord.java:238)
at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:974)
... 18 common frames omitted
[pool-18-thread-3] [FrontendWebSocketHandler] Connection closed. Session: StandardWebSocketSession[id=0, uri=/myt/websocket], CloseStatus: CloseStatus[code=1006, reason=Unable to wrap data, invalid status [CLOSED]];
[pool-18-thread-2] [GenericMessageEndpoint] Exception while sending message to the endpoint: java.lang.IllegalStateException: The remote endpoint was in state [TEXT_PARTIAL_WRITING] which is an invalid state for called method,
[pool-18-thread-1] [GenericMessageEndpoint] Exception while sending message to the endpoint: java.lang.IllegalStateException: The remote endpoint was in state [TEXT_PARTIAL_WRITING] which is an invalid state for called method,
[pool-18-thread-3] [GenericMessageEndpoint] Exception while sending message to the endpoint: java.io.IOException: java.io.IOException: Unable to wrap data, invalid status [CLOSED],
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Zamiast

TEXT_PARTIAL_READY

sesja WebSocket może już być włączona

State.TEXT_PARTIAL_WRITING

przez inny wątek, jak pokazano w kodzie tutaj
https://www.codota.com/web/ass ... L1182
https://www.codota.com/web/ass ... L1182

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się