tomcat websocket FutureToSendHandler TimeoutException

tomcat websocket推送出现停顿查找日志后发现有以下异常信息



java.io.IOException: java.util.concurrent.TimeoutException: Operation timed out after waiting [20,000] [milliseconds] to complete
	at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.handleSendFailureWithEncode(WsRemoteEndpointImplBase.java:558)
	at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.handleSendFailure(WsRemoteEndpointImplBase.java:533)
	at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessageBlock(WsRemoteEndpointImplBase.java:285)
	at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:600)
	at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:490)
	at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.onError(WsHttpUpgradeHandler.java:149)
	at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.access$300(WsHttpUpgradeHandler.java:47)
	at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onError(WsHttpUpgradeHandler.java:206)
	at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:189)
	at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198)
	at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:661)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.concurrent.TimeoutException: Operation timed out after waiting [20,000] [milliseconds] to complete
	at org.apache.tomcat.websocket.FutureToSendHandler.get(FutureToSendHandler.java:116)
	at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessageBlock(WsRemoteEndpointImplBase.java:278)
	... 15 more


tomcat的阻塞等待了20秒导致系统无法继续推送


于是我跟踪TOMCAT源代码后发现是tomcat websocket的配置问题。


tomcat官网给出如下解释



The JSR-356 Java WebSocket 1.1 implementation is only available when Tomcat is running on Java 7 or later.

Tomcat provides a number of Tomcat specific configuration options for WebSocket. It is anticipated that these will be absorbed into the WebSocket specification over time.

The write timeout used when sending WebSocket messages in blocking mode defaults to 20000 milliseconds (20 seconds). This may be changed by setting the property org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT in the user properties collection attached to the WebSocket session. The value assigned to this property should be a Longand represents the timeout to use in milliseconds. For an infinite timeout, use -1.



于是我们在项目的web.xml中增加了org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT的配置,以为如此就能解决问题

			<context-param>
				<param-name>org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT</param-name>
				<param-value>500</param-value>
			</context-param>

但是加完了之后问题依旧,又仔细阅读了下官网说明发现这玩意不是配在context-param中的,说是配在user properties中。那是个啥玩意。

于是又翻遍了tomcat源码,org.apache.tomcat.websocket.WsRemoteEndpointImplBase类里有如下获取timeout的代码


 private long getBlockingSendTimeout() {
    	
        Object obj = wsSession.getUserProperties().get(
                BLOCKING_SEND_TIMEOUT_PROPERTY);
        Long userTimeout = null;
        if (obj instanceof Long) {
            userTimeout = (Long) obj;
        }
        if (userTimeout == null) {
            return DEFAULT_BLOCKING_SEND_TIMEOUT;
        } else {
        	System.out.println(BLOCKING_SEND_TIMEOUT_PROPERTY+":"+userTimeout);
            return userTimeout.longValue();
        }
    }
其实就是在wsSession中有个userProperties的map,把属性put进去就好了。

然后就简单了,在你websocket的类的@OnOpen方法内加入以下代码即可,注意后面的时间一定要是Long型,否则上面的代码会判断不出来。

session.getUserProperties().put( "org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT",1000L);

  @OnOpen
    public void start(Session session) {
    	session.getUserProperties().put( "org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT",1000L);
        this.session = session;
        connections.add(this);
        String message = String.format("* %s %s", nickname, "has joined.");
        broadcast(message);
    }




  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值