websock报错:The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for caller

网上看到了一些关于这个错误的产生场景

参考:场景:使用websocket遇到的一个小问题 The remote endpoint was in state [TEXT_PARTIAL_WRITING] which is an invalid stat

我这里产生错误的场景是不同的,记录一下

背景

提供websocket服务的公司,其内部的系统已经与websocket server建立了长连接,图中的nginx是一个出口网关,其运维要求是出口网关与上游服务是不能建立长连接的。

而我们作为外部公司,希望使用其长连接服务,显然长连接是建立不起来了

方案

我们使用java开发websocket client,由于其不支持长连接,我们就采用了轮询的方式,每隔30s通过http upgrade来拉取一次数据

使用了@ClientEndpoint注解

伪代码

// 提供启动的时候 与nginx建立长连接

// 在onMessage方法中 每次发送http请求 获取的结果落库

这样做,在于nginx的长连接中不断发送http请求,是OK的

问题

问题是:在某些情况下会报错

[ ERROR] [2020-07-06 01:45:34] [WebSocketClient-AsyncIO-1] org.apache.tomcat.websocket.pojo.PojoEndpointBase [175] - No error handling configured for [xxx] and the following error occurred
java.io.IOException: java.util.concurrent.ExecutionException: java.io.IOException: 断开的管道

之后30秒报错

[ ERROR] [2020-07-04 15:41:42] [WebSocketClient-AsyncIO-1] org.apache.tomcat.websocket.pojo.PojoEndpointBase [175] - No error handling configured for [xxx] and the following error occurred
java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method

通过这个错误,可能得出两个结论

1. 当websocket server与client之间的socket断开(broken pipe)之后,在长连接上根据session继续发送http请求会报错

java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method

2. No error handling configured for 的原因是:没有配置@onError注解来处理

解决方案

是不是可以在onError这里重新建立一个新的socket连接呢?经过测试,这种方式是不行的,因为这样会导致前一个连接没有关闭,后面又建立了一个连接,导致多个端口对同一个remote endpoint建立连接

代码参考:

    @OnError
    public void onError(Session session, Throwable t) {
        logger.error(CommonUtil.exceptionToString(t));
        /**
         * 解决websocket服务器断开socket 导致@ClientEndPoint生成的WebScoket-AsyncIO线程退出的问题
         * 这里再次建立socket连接
         */
        WebSocketContainer container;
        try {
            container = ContainerProvider.getWebSocketContainer();
            URI r = URI.create(Const.SMK_WEBSOCKET_ADDRESS_PREFIX + Const.SMK_CENTER_MODULE);
            session = container.connectToServer(this.getClass(), r);
        } catch (DeploymentException | IOException ex) {
            logger.error(CommonUtil.exceptionToString(ex));
        }
    }

应该在onClose方法中建立一个新的socket连接

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        logger.warn("closing session => {} - {}", session, reason);
        /**
         * 解决websocket服务器断开socket 导致@ClientEndPoint生成的WebScoket-AsyncIO线程退出的问题
         * 这里再次建立socket连接
         */
        try {
            new Thread(new SmkCenterRunnable(), "smk-center-java-websocket-client").start();
        } catch (Exception e) {
            logger.error(CommonUtil.exceptionToString(e));
        }
    }

经过测试,大部分场景下其会重新建立其websocket连接。但是也存在失败的情况,后续可以加入retry策略,采用一个定时器,每隔1分钟,2分钟,4分钟...以及重试次数来尝试重新建立连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值