我正在使用Tomcat 8.0.15和Spring 4.1.5。
我已经实现了以下3个必需的函数来使用WebSocket。这非常简单。
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()));
}
}
一些客户端发送消息,其他客户端通过handleTextMessage接收消息。
在我的情况下,如果没有handleTextMessage函数,服务器程序想向客户端发送文本消息。(为此,我将WebSocketSession的Id和用户名保存到map_id中)
String websocketsesssion_id = map_id.get(username);
WebSocketSession wss = map_users.get(websocketsesssion_id);
wss.sendMessage(new TextMessage(new java.util.Date()));
以上代码运行非常好。 但是当一些客户端的WebSocketSession正在使用时,尝试同时使用会导致错误。 这意味着: 1. 一些客户端发送消息 --> 调用 handleTextMessage --> 客户端的 WebSocketSession 正在使用 2. 服务器程序想要向该客户端发送消息 --> 从映射中获取客户端的 WebSocketSession --> 尝试使用同一个 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)
作为结果,WebSocketSession被关闭,客户端必须再次打开新的WebSocketSession。因此,我的问题是:
我能否检查WebSocketSession是否正在使用中? (在handleTextMessage函数之外)
wss://
,这是否意味着没有解决方案? - Wim DeblauweTEXT_PARTIAL_WRITING
是为了防止客户端读取混合的文本响应,因此必须一次只能发送一条消息。但是服务器端的读取呢?这没有意义。 - Kimi Chiu