【问题标题】:inputstream.read() timeout seconds are counting even when the thread is not currently in the method即使线程当前不在方法中,inputstream.read() 超时秒数也会计数
【发布时间】:2014-02-14 04:25:15
【问题描述】:

我正在使用来自 Apache Commons Net 3.3 jar 的TelnetClient.class。我的问题是 setSoTimeout() 方法的行为不是预期的。据我所知,这种方法只是调用具有相同名称但在Socket.class 中设置read() 超时的方法。这是一个示例代码(IOManager 只是我为 I/O 操作制作的一个类):

telnet = new TelnetClient();
telnet.connect("localhost", 2020);
telnet.setSoTimeout(10000);

manager = new IOManager(telnet.getInputStream(), telnet.getOutputStream());
while (true) {
  System.out.println(manager.readBuffer());
  Thread.sleep(10000);
  manager.sendMessage("Peanut Butter Jelly");
}

这是我在 IOManager 类中读取的方法的代码(阅读器是一个 BufferedReader,带有启用了 soTimeout 的 telnet 输入流):

public String readBuffer() throws IOException {
        StringBuilder message = new StringBuilder();
        int len;
        char[] chars = new char[1024];
        do {
            if ((len = reader.read(chars)) != -1) {
                message.append(chars, 0, len);
                Thread.sleep(30);
            } else {
                throw new IOException("Stream closed");
            }
        } while (reader.ready());
        return message.toString();
    }

我的问题是:即使我没有在超时秒数计算的那一刻调用read()!我想要的只是尝试读取数据 10 秒,但是当我读取某些内容然后等待 10 秒并写入时,当我再次尝试读取 BOOM! java.net.SocketTimeoutException: Read timed out.

超时将立即到期!然后服务器端抛出这个:java.net.SocketException: Software caused connection abort: recv failed

我使用的进程在再次阅读之前会做很多事情,甚至在再次发送命令之前等待超过 20 分钟。当应用程序在指定的超时时间内没有得到响应时,它必须重新启动。如果我删除 Thread.sleep() 它会正确读取和发送,只要客户端无法在 10 秒内读取数据(正常)

我经常使用服务器/客户端程序和套接字。这仅在使用 TelnetClient 时发生。可能是什么问题呢?为什么会有这种行为?如果我不能让它工作,我想我会使用 Callabe 和 Future 接口,但那是另一个线程只是为了读取(哎呀,我实际上与那个 Telnet 服务器建立了多个连接)。

感谢阅读。

【问题讨论】:

  • 套接字超时的行为与您描述的不同。你的观察有问题,代码也可能有问题。由于您尚未发布,因此无法发表进一步评论。
  • 我刚刚发布了代码:)

标签: java sockets telnet apache-commons-net


【解决方案1】:

我找不到方法。这种行为总是出乎意料,所以我用这段代码做到了:

我的 ExecutorService 空间仅可容纳 1 个线程。我从 Callable 通用接口实现 call() 方法(这就是为什么我可以返回 String 或任何我想要的)。

ExecutorService executor = Executors.newFixedThreadPool(1);
Callable<String> readTask = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return readBuffer();
            }
        };

我重载了 readBuffer() 方法。我有一个读取接受超时参数:

 public String readBuffer(long timeout) throws ExecutionException, TimeoutException {
        return executor.submit(readTask).get(timeout, TimeUnit.MILLISECONDS);
    }

执行程序提交读取缓冲区的任务,直到没有其他内容可读取或直到超时(以毫秒为单位)到期。

它按预期工作,没有性能问题。

【讨论】:

    【解决方案2】:

    我遇到了这个问题,通过关闭TelnetClient中的阅读器线程解决了它:

    telnet = new TelnetClient();
    telnet.setReaderThread(false); // This prevents the timeout bug
    telnet.connect("localhost", 2020);
    telnet.setSoTimeout(10000);
    

    【讨论】:

      猜你喜欢
      • 2014-05-15
      • 1970-01-01
      • 2013-06-23
      • 2015-02-05
      • 2012-12-09
      • 2021-01-03
      • 1970-01-01
      • 2020-03-13
      • 2021-11-26
      相关资源
      最近更新 更多