| | |
| | | } |
| | | catch (TimeoutException ex) |
| | | { |
| | | closeInFlight(); |
| | | interruptRead(); |
| | | pending.cancel(true); |
| | | throw new BtsTransportException(BtsTransportException.Reason.TIMEOUT, |
| | | "BTS 管道应答超时(" + responseTimeoutMs + " ms):" + pipePath, ex); |
| | | } |
| | | catch (InterruptedException ex) |
| | | { |
| | | closeInFlight(); |
| | | interruptRead(); |
| | | pending.cancel(true); |
| | | Thread.currentThread().interrupt(); |
| | | throw new BtsTransportException(BtsTransportException.Reason.IO_FAILURE, |
| | |
| | | try { pipe.close(); } catch (IOException ignored) { } |
| | | } |
| | | |
| | | /** |
| | | * 在独立线程里关掉在途句柄,用来打断阻塞中的读。 |
| | | * |
| | | * <p>为什么不自己关:实测关闭一条"服务端不作答的连接"**本身会阻塞**(关闭要等 SMB 层回收), |
| | | * 那样超时就白设了——调用线程照样被钉死。而这个实例是串行执行的(BTS 一条连接只服务一条请求, |
| | | * 注册表也按实例串行),一条不响应的命令足以把该实例之后的所有请求堵住。 |
| | | * 关闭线程是守护线程且不等它结束:最坏情况是每次超时留一个挂着的关闭线程, |
| | | * 而超时本身应当罕见——真出现"某客户端不支持某命令",它的表现正是每次都无应答。 |
| | | */ |
| | | private void interruptRead() |
| | | { |
| | | RandomAccessFile pipe = inFlight; |
| | | if (pipe == null) return; |
| | | Thread closer = new Thread(() -> { |
| | | try { pipe.close(); } catch (IOException ignored) { } |
| | | }, "neware-bts-pipe-close"); |
| | | closer.setDaemon(true); |
| | | closer.start(); |
| | | } |
| | | |
| | | @Override |
| | | public void close() |
| | | { |