ric*_*icb 5 java jersey server-sent-events jersey-2.0
我们使用 Jersey 服务器发送事件 (SSE) 来允许应用程序的远程组件侦听 Jersey/Tomcat 服务器引发的事件。这很好用。
然而,至关重要的是我们的服务器拥有当前连接的侦听器(我们的远程组件)的准确列表。为此,我们的服务器每五秒向每个调用者发送一条小消息(通过 eventOutput.write)。如果我们的远程组件在 SSE 连接时关闭,或者远程计算机在 SSE 连接时关闭,我们服务器的 eventOutput.write 会抛出如下所示的 ClientAbortException/SocketException 异常。这很完美:我们捕获异常,将该调用者标记为不再连接,然后继续。
现在,针对问题。正如我所提到的,如果我们的远程组件软件未运行,或者运行该软件的计算机已关闭,则 eventOutput.write 会引发异常。但是,在两种情况下,对不再连接的计算机调用 eventOutput.write 不会引发异常:1) 如果在调用者连接 SSE 时简单地拔出远程计算机的以太网电缆,以及 2) 如果当调用者通过 SSE 连接时,远程计算机中的网络适配器被关闭(即通过管理操作)。在这两种情况下,我们可以在几个小时内每五秒调用一次 eventOutput.write 到远程计算机,并且不会引发异常。这使得无法检测到远程计算机不再连接。
我看到 EventOutput (和 ChunkedOutput) 的方法和属性非常少,但我想知道是否有任何方法可以配置或使用它,从而在写入已通过以太网断开连接的远程计算机时引发异常电缆已拔出或网络适配器已关闭。
这是在 eventOutput.write 确实抛出我们想要的异常的情况下得到的(好/有用)异常:
org.apache.catalina.connector.ClientAbortException: null
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:371) ~[catalina.jar:7.0.53]
at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:333) ~[catalina.jar:7.0.53]
at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:101) ~[catalina.jar:7.0.53]
at org.glassfish.jersey.servlet.internal.ResponseWriter$NonCloseableOutputStreamWrapper.flush(ResponseWriter.java:303) ~[jaxrs-ri-2.13.jar:2.13.]
at org.glassfish.jersey.message.internal.CommittingOutputStream.flush(CommittingOutputStream.java:292) ~[jaxrs-ri-2.13.jar:2.13.]
at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:240) ~[jaxrs-ri-2.13.jar:2.13.]
at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:190) ~[jaxrs-ri-2.13.jar:2.13.]
at org.glassfish.jersey.internal.Errors.process(Errors.java:315) ~[jaxrs-ri-2.13.jar:2.13.]
at org.glassfish.jersey.internal.Errors.process(Errors.java:242) ~[jaxrs-ri-2.13.jar:2.13.]
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:347) ~[jaxrs-ri-2.13.jar:2.13.]
at org.glassfish.jersey.server.ChunkedOutput.flushQueue(ChunkedOutput.java:190) ~[jaxrs-ri-2.13.jar:2.13.]
at org.glassfish.jersey.server.ChunkedOutput.write(ChunkedOutput.java:180) ~[jaxrs-ri-2.13.jar:2.13.]
at com.appserver.webservice.AgentSsePollingManager$ConnectionChecker.run(AgentSsePollingManager.java:174) ~[AgentSsePollingManager$ConnectionChecker.class:na]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [na:1.7.0_71]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304) [na:1.7.0_71]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178) [na:1.7.0_71]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.7.0_71]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_71]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_71]
at java.lang.Thread.run(Thread.java:745) [na:1.7.0_71]
Caused by: java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method) ~[na:1.7.0_71]
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113) ~[na:1.7.0_71]
at java.net.SocketOutputStream.write(SocketOutputStream.java:159) ~[na:1.7.0_71]
at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215) ~[tomcat-coyote.jar:7.0.53]
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480) ~[tomcat-coyote.jar:7.0.53]
at org.apache.coyote.http11.InternalOutputBuffer.flush(InternalOutputBuffer.java:119) ~[tomcat-coyote.jar:7.0.53]
at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:799) ~[tomcat-coyote.jar:7.0.53]
at org.apache.coyote.Response.action(Response.java:174) ~[tomcat-coyote.jar:7.0.53]
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:366) ~[catalina.jar:7.0.53]
... 19 common frames omitted
Run Code Online (Sandbox Code Playgroud)
我认为即使 Jersey 添加了可从套接字接口访问的所有信息,也无法通过在 SSE 套接字周围添加代码来解决所有可能的故障。唯一可行的解决方案是适当的双向通信。在 SSE 分块输出流的情况下,拉动电缆不会导致任何中断,因为没有任何内容可以告诉它远程主机现在无法访问(直到操作系统关闭套接字)。
您的第一步是正确的 - 每 N 秒实施一次心跳。然后你需要做的就是每隔一段时间用另一个小的 http 调用来报告,这样你仍然可以监听。您可以每 5 秒或每分钟进行一次确认 - 取决于您需要多快的速度检测问题。
您可以在同一个 Jersey 资源中通过实现 @POST 来完成此操作(用 RESTful 术语来说,它是“创建您接收事件的新确认”)。
注意:在网络中断的情况下,浏览器能够自行重新建立 SSE 连接,无需摆弄它。
| 归档时间: |
|
| 查看次数: |
1555 次 |
| 最近记录: |