提问人:Tudor 提问时间:2/20/2019 更新时间:3/19/2019 访问量:1114
Java bayeux 客户端在空闲时断开连接并出现 TimeoutException
Java bayeux client disconnects with TimeoutException when idle
问:
我正在初始化Bayeux客户端:
SslContextFactory sslContextFactory = new SslContextFactory(true);
HttpClient httpClient = new HttpClient(sslContextFactory);
httpClient.start();
Map<String, Object> options = new HashMap<String, Object>();
ClientTransport transport = new LongPollingTransport(options, httpClient);
BayeuxClient client = new BayeuxClient("https://localhost:8483/cometd/", transport);
client.handshake();
boolean handshaken = client.waitFor(20000, BayeuxClient.State.CONNECTED);
if (!handshaken) {
LOGGER.info("Failed to handshake");
throw new RuntimeException("Failed to handshake");
}
我用它来与服务器进行一些通信,它可以工作,它订阅频道,发送,接收,然后我让它闲置一段时间。我遇到以下异常:
java.util.concurrent.TimeoutException: Idle timeout 20000 ms
at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onIdleExpired(HttpConnectionOverHTTP.java:145)
at org.eclipse.jetty.io.ssl.SslConnection.onIdleExpired(SslConnection.java:286)
at org.eclipse.jetty.io.AbstractEndPoint.onIdleExpired(AbstractEndPoint.java:401)
at org.eclipse.jetty.io.IdleTimeout.checkIdleTimeout(IdleTimeout.java:166)
at org.eclipse.jetty.io.IdleTimeout$1.run(IdleTimeout.java:50)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
以及以下多次:
java.nio.channels.ClosedChannelException: null
at org.eclipse.jetty.io.WriteFlusher.onClose(WriteFlusher.java:502)
at org.eclipse.jetty.io.AbstractEndPoint.onClose(AbstractEndPoint.java:353)
at org.eclipse.jetty.io.ChannelEndPoint.onClose(ChannelEndPoint.java:216)
at org.eclipse.jetty.io.AbstractEndPoint.doOnClose(AbstractEndPoint.java:225)
at org.eclipse.jetty.io.AbstractEndPoint.close(AbstractEndPoint.java:192)
at org.eclipse.jetty.io.AbstractEndPoint.close(AbstractEndPoint.java:175)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.doClose(SslConnection.java:1132)
at org.eclipse.jetty.io.AbstractEndPoint.doOnClose(AbstractEndPoint.java:220)
at org.eclipse.jetty.io.AbstractEndPoint.close(AbstractEndPoint.java:192)
at org.eclipse.jetty.io.AbstractEndPoint.close(AbstractEndPoint.java:175)
at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.close(HttpConnectionOverHTTP.java:195)
at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onIdleExpired(HttpConnectionOverHTTP.java:145)
at org.eclipse.jetty.io.ssl.SslConnection.onIdleExpired(SslConnection.java:286)
at org.eclipse.jetty.io.AbstractEndPoint.onIdleExpired(AbstractEndPoint.java:401)
at org.eclipse.jetty.io.IdleTimeout.checkIdleTimeout(IdleTimeout.java:166)
at org.eclipse.jetty.io.IdleTimeout$1.run(IdleTimeout.java:50)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
如果我让它保持忙碌,它不会失败。我尝试更改httpclient的超时,但这只会延迟问题。为什么 Bayeux 关闭通道而不是进行轮询?我使用最新版本org.cometd.java 4.0.2。
另外需要注意的是,我有一个可以毫无问题地工作的 javascript 客户端。
有人可以帮忙吗?
答:
0赞
sbordet
2/21/2019
#1
默认检测信号在服务器端由参数控制,默认为 30 秒。
这意味着,当系统处于空闲状态时,每 30 秒进行一次长轮询。timeout
您已将客户端配置为 20 秒,这从异常堆栈跟踪中可以明显看出。idleTimeout
当系统处于空闲状态时,客户端将在检测信号(长轮询)响应之前超时连接,从而导致您看到的错误。
将客户端配置为大于检测信号的值,或者 - 等效地 - 将检测信号设置为小于客户端的值 就足够了。idleTimeout
timeout
timeout
idleTimeout
评论
0赞
Tudor
3/8/2019
我放置任何 idleTimeout,如果我放大它,我不再得到 TimeoutException,但我仍然得到 ClosedChannelException。
0赞
sbordet
3/8/2019
在stackoverflow中很难进行故障排除。欢迎您在 CometD 项目中提出问题,我们可以继续讨论。一个大胆的猜测是,在客户端和正在关闭连接的 CometD 服务器之间有其他东西,或者您没有在客户端和服务器中正确配置空闲超时。打开问题并附加 DEBUG 日志。您是否尝试过部署 CometD 演示,它是否有效?
1赞
Tudor
3/19/2019
#2
事实证明,我阻止了 cometD 线程:
我构建了一个命令行工具来检查服务器,当我收到一条消息(带有来自 cometD 的线程)时,我保留了该线程以供用户输入。如果我保持该线程足够长的时间,彗星 D 就会与上述异常断开连接。
解决方案:当您收到来自 CometD 的消息时,不要持有它,请使用新线程。
评论