我在使用websocket时遇到了一些问题:
java.io.IOException: Broken Pipe
- 客户端无法接收消息
简短总结
我需要知道的主要内容:
- 请列举所有可能导致客户端关闭连接的情况(除了刷新或关闭标签页)。
- 除了服务器向已经断开的连接发送消息以外,是否还会出现“Broken Pipe”异常?如果是,那么如何处理?
- 服务器为什么有时不会发送消息,即使它确实发送了心跳包?(当发生这种情况时,我需要重新启动应用程序才能让它再次工作。这是一个可怕的解决方法,因为它已经在生产中使用了。)
我有一个使用
websockets
的SpringMVC
项目;客户端使用SockJS
,服务端使用org.springframework.web.socket.handler.TextWebSocketHandler
。
一个JSON
在服务器端生成并发送到客户端。有时候,我会遇到java.io.IOException: Broken Pipe
异常。我在谷歌和StackOverflow上搜索了很多东西,但是找到了很多我不理解的东西,但原因可能是连接已经在客户端关闭,但服务器仍在发送消息(例如心跳包)。这听起来合理吗?此异常出现的其他原因是什么?除了刷新或关闭标签页,导致客户端关闭连接的原因有哪些?
还有,有时候客户端无法从服务器接收任何消息,尽管服务器应该发送它们。我在发送消息之前和之后进行记录,两个记录语句都被打印出来。有人知道为什么会发生这种情况吗?Chrome的控制台日志中没有错误。刷新页面不起作用,我需要重新启动Spring项目...
如果您需要更多信息,请留言。
客户端
function connect() {
var socket = new SockJS('/ws/foo');
socket.onopen = function () {
socket.send(fooId); // ask server for Foo with id fooId.
};
socket.onmessage = function (e) {
var foo = JSON.parse(e.data);
// Do something with foo.
};
}
服务器端
服务
@Service
public class FooService implements InitializingBean {
public void updateFoo(...) {
// Update some fields of Foo.
...
// Send foo to clients.
FooUpdatesHandler.sendFooToSubscribers(foo);
}
}
WebSocket处理程序
public class FooUpdatesHandler extends ConcurrentTextWebSocketHandler {
// ConcurrentTextWebSocketHandler taken from https://github.com/RWTH-i5-IDSG/BikeMan (Apache License version 2.0)
private static final Logger logger = LoggerFactory.getLogger(FooUpdatesHandler.class);
private static final ConcurrentHashMap<String, ConcurrentHashMap<String, WebSocketSession>> fooSubscriptions =
new ConcurrentHashMap<>();
public static void sendFooToSubscribers(Foo foo) {
Map<String, WebSocketSession> sessionMap = fooSubscriptions.get(foo.getId());
if (sessionMap != null) {
String fooJson = null;
try {
fooJson = new ObjectMapper().writeValueAsString(foo);
} catch (JsonProcessingException ignored) {
return;
}
for (WebSocketSession subscription : sessionMap.values()) {
try {
logger.info("[fooId={} sessionId={}] Sending foo...", foo.getId(), subscription.getId());
subscription.sendMessage(new TextMessage(fooJson));
logger.info("[fooId={} sessionId={}] Foo send.", foo.getId(), subscription.getId());
} catch (IOException e) {
logger.error("Socket sendFooToSubscribers [fooId={}], exception: ", foo.getId(), e);
}
}
}
}
}