2

我想使用 BufferedReader 的 readline 方法识别用户是否发送了文本。当用户没有发送任何东西时,线程一直在休眠。有没有办法做到这一点?我尝试了很长时间,但还没有成功..我想我必须识别是否按下了ENTER键..但我不知道该怎么做..我的程序界面是控制台..

问题是:我有一个客户端-服务器程序。当客户端输入消息时,消息会在另一个用户/客户端的屏幕上提示。但是,如果用户在 10 秒内没有发送消息,我希望屏幕上出现一条消息。所以我有一个 Thread.sleep(1000)。问题是我不知道什么时候唤醒线程。

while((mensagem == null) || (!mensagem.trim().equals(""))) { 
      Thread.sleep(10000); 
      sendToAll(output, "[Your turn] ", ""); 
      mensagem = input.readLine(); 
   }

最后一行也不正确,因为我不想强迫用户输入,而这种方式是我强迫的,因为我在 input.readLine() 上停止。

解决方案:我使用 setSoTimeout(10000) 方法解决了问题。这是代码:

public Server(Socket socket) throws SocketException{
   this.connection = socket;
   this.connection.setSoTimeout(10000);
}

public void run(){
   [...]
   while((msg != null) && !(msg.trim().equals(""))){        
      try{  
         msg = input.readLine();
     sendToAll(output, ": ", msg);  
      } catch (SocketTimeoutException e) {
     sendToAll(output, "Time out ", "");
      }       
}

谢谢大家的想法!!:)

4

2 回答 2

2

你读了整行是这样的:

String in;
while ((in = br.readLine()) != null) {
    // If this is triggered, in contains a whole line and if the input came from console that means enter was pressed
}

编辑:回复您的编辑:

input.readLine()是一种阻塞方法。它将继续尝试读取整行,直到收到一行、抛出异常或到达 EOF。您的问题是您想要 10 秒超时。如我错了请纠正我。

执行此操作的方法是创建一个不会被调用阻塞的计时器或线程,以中断您的 .readLine() 调用。您应该已经在其自己的线程中拥有所有 I/O,因此您需要从另一个线程(主线程或使用计时器)创建一个定时事件,该事件将中断被阻塞的线程。使用 Timer 的示例,在循环之前添加:

java.util.Timer t = new java.util.Timer();
t.schedule(new TimerTask() {
    @Override
    public void run() { 
        IOHandlerClass.this.interrupt();
    }
}, 10000);

用放置此代码的类的名称替换 IOHandlerClass (您没有发布代码,所以我不知道名称)。

现在,除非您停止计时器,否则这将导致 10 秒后引发 InterruptException。因此,用 try-catch 包围您的代码以捕获该异常,如果它被抛出,您将显示错误消息。如果您确实在 10 秒超时内得到有效响应,请记住取消计时器。

于 2013-08-18T22:48:54.333 回答
1

您需要了解 Java 端和控制台端发生了什么。

在 Java 端,readLine()调用只是尝试读取字符,直到它看到有效的“行尾”序列,即输入流的结尾。这是一个阻塞调用,无法在您使用的 API 中指定超时。

在控制台端,控制台正在监视键盘事件并将它们累积在行缓冲区中:

  • 当它看到数据字符(数字、字母等)的关键事件时,它会将字符添加到缓冲区中。
  • 当它看到一个元字符(例如“删除”)时,它会在行缓冲区上执行适当的编辑。例如,它可能会在“光标”位置从行缓冲区中删除一个字符。
  • 当它看到一个 ENTER 键时,它将一个行尾序列添加到行缓冲区,并发送该行。

详细信息将取决于控制台程序以及用户如何配置它。然而,事实仍然是,在用户键入 ENTER 之前,不会将任何内容发送到将控制台连接到 Java 应用程序的“管道”。简而言之,Java 应用程序将看不到任何东西。

这意味着 Java 应用程序无法判断用户是否正在键入。


那么Java应用程序能做什么呢?

  • readLine()您可以在几秒/分钟后使用 Timer 向阻塞的 Java 线程(执行调用的线程)发送中断。这将导致readLine()调用解除阻塞并引发 IOException。但是,这种方法存在问题:

    • 有一个潜在的竞争条件,即在readLine()调用完成后定时器触发,并且中断转到应用程序本身。这可能会导致问题,具体取决于应用程序对中断的处理方式。您应该能够使用主线程在readLine调用返回时设置的正确同步标志来避免这种情况。

    • 目前尚不完全清楚,但有迹象表明,如果您在管道上遇到中断,则底层通道会自动关闭。这意味着您不能要求用户提供更多输入。

  • 第二种方法可能是用使用 NIO 通道选择器的东西替换您的BufferedReader/代码。readLine()除其他外,aSelector允许您等待通道具有可读数据的超时。然后,您需要在此之上实现缓冲和 readline。

  • 如果您想知道用户是否在控制台上键入,您需要将控制台置于非行编辑模式。这不能在纯 Java 中完成,但是有 3rd-party 库可以做这种事情。

于 2013-08-19T00:20:59.017 回答