Spring websockets 管道损坏和客户端未接收消息

2022-09-04 23:24:27

我在使用websockets时遇到了一些问题:

  • java.io.IOException: Broken Pipe
  • 客户端未收到消息
    TL;DR

我想知道的主要事情:

  • 请列出客户端关闭连接的所有可能情况(刷新或关闭选项卡除外)。
  • 除了服务器通过断开的连接向客户端发送消息之外,是否还会发生管道损坏异常?如果是,那么如何?
  • 尽管服务器确实发送检测信号,但服务器不发送消息的可能情况是什么?(发生这种情况时,我需要重新启动应用程序才能使其再次工作。这是一个糟糕的解决方案,因为它已经在生产中。


我有一个项目使用; 客户端和服务器端。SpringMVCwebsocketsSockJSorg.springframework.web.socket.handler.TextWebSocketHandler

A 生成服务器端并发送到客户端。有时,我得到一个.我谷歌/ StackOverflow了很多,发现太多我不明白的东西,但原因可能是连接关闭客户端,服务器仍然发送消息(例如,心跳)。这听起来还好吗?出现此异常的其他原因是什么?客户端关闭连接的原因是什么(除了刷新或关闭选项卡)?JSONjava.io.IOException: Broken Pipe

此外,有时客户端不会从服务器获取任何消息,尽管服务器应该发送它们。我在发送消息之前和之后进行记录,并且两个日志语句都被打印出来。有没有人知道为什么会发生这种情况?我在 Chrome 的控制台日志中没有错误。刷新页面不起作用,我需要重新启动弹簧项目...

如果您需要更多信息,请发表评论。


客户端
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);
    }
}

WebSocketHandler

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

答案 1

只是一个有根据的猜测:检查你的网络装备。也许有一个错误配置的防火墙终止了这些连接;或者更糟糕的是,网络设备损坏导致连接终止。如果您的服务器有多个 NIC(很可能是这种情况),则使用这些 NIC 或通过不同的 NIC 连接到服务器时也可能存在一些配置错误。


答案 2

如果此问题意外发生,则可能是您的任何缓存都有问题 - 请检查spring或SocksJS是否具有自己的缓存以进行套接字交互。

这是否发生在您的设备(或您控制的设备上)?

此外,我可以建议你使用一些网络数据包分析器,如wireshark。使用这样的工具,您将看到当前的网络活动“在线”

一些外部原因可能会在不正确停止连接的情况下取消连接(并且如果不进行连接检查,则无法对其进行管理):

  • 设备挂起/关机
  • 网络故障
  • 浏览器因某些错误而关闭

我认为这是破坏连接的可能原因的完整列表的一小部分。


推荐