有没有办法知道用户是否使用readline()方法按下了ENTER键? - Java

时间:2013-08-18 22:43:46

标签: java multithreading readline

我想知道用户是否使用BufferedReader中的readline方法发送了文本。当用户没有发送任何内容时,线程会保持睡眠状态。有没有办法做到这一点?我已经尝试了很长时间,但还没有成功..我想我必须认识到是否按下了一个ENTER键..但我知道如何做到这一点..我的程序界面是控制台.. < / p>

问题是:我有一个客户端 - 服务器程序。当客户端输入消息时,该消息会在另一个用户/客户端的屏幕上提示。但是,如果用户在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 ", "");
      }       
}

谢谢大家的想法!! :)

2 个答案:

答案 0 :(得分: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)您需要创建一个将中断被阻塞线程的定时事件。使用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秒内超时内获得有效响应,请记得取消计时器。

答案 1 :(得分:1)

您需要了解Java端和控制台端的内容。

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

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

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

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

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


那么Java应用程序可以做什么?

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

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

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

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

  • 如果您想知道用户是否在控制台上输入了,您需要将控制台置于非线路编辑模式。这不能用纯Java完成,但有第三方库可以做这种事情。