Java bayeux客户端在空闲时与TimeoutException断开连接

问题描述 投票:0回答:2

我正在初始化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客户端。

有人可以帮忙吗?

java comet long-polling cometd bayeux
2个回答
0
投票

默认心跳在服务器端由timeout参数控制,默认情况下为30秒。这意味着当系统空闲时,长轮询每30秒发生一次。

您已将客户端idleTimeout配置为20秒,因为从您的异常堆栈跟踪中可以看出这一点。

当系统空闲时,客户端将在心跳(长轮询)响应之前超时连接,从而导致您看到的错误。

您应该将客户端idleTimeout配置为大于heartbeat timeout的值,或者 - 等效地 - 将heartbeat timeout设置为比客户端idleTimeout更小的值。


0
投票

事实证明我阻止了cometD线程:

我构建了一个命令行工具来检查服务器,当我收到一条消息(带有来自cometD的线程)时,我持有该用户输入的线程。如果我持有该线程足够长,则断开连接上述异常。

解决方案:当您收到来自CometD的消息时,请不要按住它,使用新线程。

© www.soinside.com 2019 - 2024. All rights reserved.