2015-03-12 26 views
8

Używam tomcat 8.0.15, wiosna 4.1.5.WebSocket Zdalny punkt końcowy był w stanie [TEXT_PARTIAL_WRITING]

Zaimplementowałem 3 obowiązkowe funkcje korzystania z websocket, jak poniżej. To 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())); 
    } 
} 

Niektóre klient wysyła wiadomość, a inni klienci otrzymują wiadomość za pomocą handleTextMessage.

W moim przypadku, bez funkcji handleTextMessage, program serwera chce wysłać wiadomość tekstową do klientów. (w tym ja zapisane WebSocketSession identyfikatora i nazwy użytkownika do 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. Kiedy jednak klient WebSocketSession jest w użyciu i próbuje użyć jednocześnie, powoduje to błąd. Oznacza to, że 1. klient wysyła wiadomość -> nazywa się handleTextMessage -> WebSocketSession klienta używa 2. program serwera chce wysłać wiadomość do tego klienta -> pobranie klienta WebSocketSession z mapy -> spróbuj wysłać wiadomość z taką samą 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 WebSocketSession jest zamknięta, a klient musi ponownie otworzyć nową WebSocketSession.

Więc moje pytanie brzmi:

mogę sprawdzić, czy WebSocketSession jest w użyciu, czy nie? (poza funkcją handleTextMessage)

Odpowiedz

11

Problemem jest to, że kilka wątek postaram się napisać w tym samym czasie na gnieździe tak:

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

Podczas synchronizowania sendMessage() połączeń pozwala na WS:// connection, to nie pomaga dla wss://, i.e. SSL/TLS connection. Jest to 100% niepowodzenie, jeśli próbujesz wysył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], 
Powiązane problemy