WebSocket The remote endpoint was in the state [TEXT_PARTIAL_WRITING]

I am using tomcat 8.0.15, spring 4.1.5.

I have implemented 3 required functions for using websocket, as shown below. It is very simple.

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())); } } 

Some clients send a message, while other clients receive a message using handleTextMessage.

In my case, without the handleTextMessage function, the server program wants to send a text message to clients. (for this, I saved the WebSocketSession id and username in map_id)

 String websocketsesssion_id = map_id.get(username); WebSocketSession wss = map_users.get(websocketsesssion_id); wss.sendMessage(new TextMessage(new java.util.Date())); 

It works very well on code. But when some WebSocketSession client is used and trying to use at the same time, it makes an error. This means 1. some message is called to send the client β†’ handleTextMessage β†’ the WebSocketSession client uses 2. the server program wants to send a message to this client β†’ receive the client WebSocketSession from the card β†’ try to send a message with the same 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) 

As a result, WebSocketSession is closed, and the client must open a new WebSocketSession again.

So my question is:

Can I check if WebSocketSession is used or not? (outside handleTextMessage function)

+8
java spring
source share
2 answers

The problem is that several threads are trying to write to the socket at the same time so that:

try:

 String websocketsesssion_id = map_id.get(username); WebSocketSession wss = map_users.get(websocketsesssion_id); synchronized(wss) { wss.sendMessage(new TextMessage(new java.util.Date())); } 
+11
source share

While synchronizing sendMessage() calls helps for a ws: // connection, it does not help for a wss://, ie SSL/TLS connection . This is a 100% failure if you try to send partial messages while reading partial messages. I tested it on Spring Boot 1.4.2 RELEASE (tomcat 8.5.6)

Same thing with tomcat 8.5.9. See below the trace stack.

 [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], 
+1
source share

All Articles