【问题标题】:Spring websockets Broken pipe & client not receiving messagesSpring websockets Broken pipe & Client 未收到消息
【发布时间】:2017-03-28 08:04:09
【问题描述】:

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

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

我想知道的主要事情:

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


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

JSON 在服务器端生成并发送到客户端。有时,我会收到java.io.IOException: Broken Pipe。我google/StackOverflowed了很多,发现太多我不明白的东西,但原因可能是客户端关闭了连接,服务器仍然发送消息(例如,心跳)。这听起来好吗?出现此异常的其他原因是什么?客户端关闭连接的原因是什么(除了刷新或关闭标签页)?

此外,有时客户端不会从服务器获得任何消息,尽管服务器应该发送它们。我在发送消息之前和之后记录,并且打印了两个日志语句。有谁知道为什么会发生这种情况?我在 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);
    }
}

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

【问题讨论】:

    标签: java spring websocket sockjs


    【解决方案1】:

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

    【讨论】:

    • 奇怪的是,通常一切都很好。多个设备(移动设备和笔记本电脑)具有 websocket 连接,每个设备都获取 Foo 的 JSON。但有时(+/- 2 周一次)会发生“重”断管(请参阅我在@Pavel Uvarov 的回答中的评论)。 websocket 连接仍然建立,服务器仍然发送心跳,只是不再发送 Foo 的 JSON。我不认为这是防火墙的事情。还有其他想法吗?
    • 这是否会影响“严重”损坏管道后的任何客户端 - 异常,还是仅影响“导致”异常的特定客户端?
    • 它影响所有客户端。当它坏了(所以没有 JSON)时,客户会联系我。我通过在多个选项卡中打开网站来测试它是否真的被破坏了。当“重”断管发生时,所有选项卡都有相同的问题。唯一的解决方案是在生产服务器上重新启动 java 程序。
    【解决方案2】:

    如果这个问题是偶然发生的,那么你的任何缓存都可能有问题 - 请检查 spring 或 SocksJS 是否有自己的用于套接字交互的缓存。

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

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

    在不正确停止连接的情况下可能会破坏连接的一些外部原因(如果没有连接检查,您将无法管理它):

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

    我认为这只是破坏连接的可能原因的一小部分。

    【讨论】:

    • 它发生在手机和笔记本电脑上。
    • 有不同“种类”的断管异常。我可以通过多次刷新浏览器自己生成一个,但是在最后一次刷新之后一切仍然正常(然后服务器仍然将 Foo 的 JSON 发送到客户端)。但有时我得到一个非常“重”的 Broken Pipe 异常,服务器不再发送 JSON(即使我刷新页面)。奇怪的是,服务器仍然发送心跳并且服务器仍然记录“发送消息”和“消息发送”(Session.sendMessage 方法之前和之后的日志。我需要重新启动整个java程序来解决这个问题......
    • 知道为什么会出现“重”断管吗?不幸的是,这不是因为您列出的原因。
    • @J.Kamans 你用任何网络数据包分析器检查过网络交互吗?
    • 我使用 Chrome,按 F12,转到选项卡网络。在那里我看到“websocket”,我可以看到所有的 websocket 消息。当一切正常时,我会看到“o”(打开)、“h”(心跳)以及 JSON。 ![Websocket frames Chrome.png](postimg.org/image/rf7dm6mmr)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    • 2021-06-06
    • 2020-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多