2015-03-12 16 views
8

Tôi đang sử dụng tomcat 8.0.15, mùa xuân 4.1.5.WebSocket Điểm cuối từ xa đã ở trạng thái [TEXT_PARTIAL_WRITING]

Tôi đã triển khai 3 chức năng bắt buộc để sử dụng websocket như dưới đây. Rất đơn giản.

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

Một số khách hàng gửi tin nhắn và các khách hàng khác nhận được tin nhắn bằng handleTextMessage.

Trong trường hợp của tôi, không có hàm handleTextMessage, chương trình máy chủ muốn gửi tin nhắn văn bản tới khách hàng. (cho điều này tôi đã lưu của WebSocketSession Id và tên người dùng vào map_id)

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

Trên đang hoạt động rất tốt. Nhưng khi một số WebSocketSession của khách hàng được sử dụng và cố gắng sử dụng đồng thời, nó sẽ gây ra lỗi. Nó có nghĩa là 1. một số khách hàng gửi tin nhắn -> handleTextMessage được gọi là -> WebSocketSession của khách hàng đang sử dụng 2. chương trình máy chủ muốn gửi tin nhắn cho khách hàng đó -> lấy WebSocketSession của khách hàng từ bản đồ -> cố gắng gửi tin nhắn với cùng 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) 

Kết quả là WebSocketSession bị đóng và khách hàng phải mở lại WebSocketSession mới.

Vì vậy, câu hỏi của tôi là:

Tôi có thể kiểm tra xem WebSocketSession có đang được sử dụng hay không? (ngoài chức năng handleTextMessage)

Trả lời

11

Vấn đề là nhiều chủ đề cố gắng viết trong cùng thời gian trên ổ cắm vậy:

thử:

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

Trong khi đồng bộ hóa sendMessage() cuộc gọi giúp cho ws:// kết nối, nó không giúp cho wss://, i.e. SSL/TLS connection. Nó là 100% thất bại nếu bạn cố gắng gửi một phần tin nhắn trong khi đọc một phần tin nhắn. Tôi đã thử nghiệm nó trên Spring Boot 1.4.2 RELEASE (tomcat 8.5.6)

Tương tự với tomcat 8.5.9. Xem dấu vết ngăn xếp bên dưới.

[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], 
Các vấn đề liên quan