2013-08-18 27 views
2

我想識別用戶是否使用BufferedReader中的readline方法發送文本。雖然用戶沒有發送任何內容,但Thread保持睡眠狀態。有沒有辦法做到這一點?我想了很長時間,但沒有成功..我想我必須承認如果一個ENTER鍵被按下..但我不知道如何做到這一點..我的程序的界面是控制檯..有沒有辦法知道用戶是否使用readline()方法按下了ENTER鍵? - Java

問題是:我有一個客戶端服務器程序。當客戶端輸入消息時,消息在另一個用戶/客戶端的屏幕上提示。但是,如果用戶在10秒內沒有發送消息,我想要一條消息出現在屏幕上。所以我有一個Thread.sleep(1000)。問題是我不知道何時喚醒線程。

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

最後一行是不是也是正確的,因爲我不想強迫用戶輸入,這樣一來,我迫使,因爲我停止input.readLine()。

SOLUTION: 我使用方法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 ", ""); 
     }  
} 

謝謝大家的想法! :)

+0

什麼問題?你嘗試了什麼? – Xabster

+1

'if(bufferedReader.read()=='\ n')'? –

+0

這是你在找什麼[設置超時限制爲readline](http://stackoverflow.com/questions/7937668/setting-a-time-out-limit-to-readline) ? – Pshemo

回答

1

您需要了解這裏發生了什麼,在Java端和控制檯端。

在Java方面,readLine()調用只是試圖讀取字符,直到它看到有效的「行尾」序列,輸入流的結束。這是一個阻塞調用,並且無法在您正在使用的API中指定超時。

在控制檯端,控制檯是看鍵盤事件和在線緩衝器中積累他們:

  • 當它看到的一個關鍵事件數據字符(數字,字母,等等),它增加了字符到緩衝區。
  • 當它看到一個元字符(例如「刪除」)時,它會在行緩衝區上執行相應的編輯。例如,它可能會從'cursor'位置的行緩衝區中刪除一個字符。
  • 當它看到一個ENTER鍵時,它將一個行尾序列添加到行緩衝區,併發送行。

具體取決於控制檯程序以及用戶如何配置它。但是,事實仍然是,直到用戶輸入ENTER,什麼都不會發送到將控制檯連接到Java應用程序的「管道」。簡而言之,Java應用程序不會看到任何東西。

這意味着Java應用程序無法判斷用戶是否正在輸入。


那麼Java應用程序可以做什麼?

  • 你可以使用一個定時器幾秒/分鐘後發送中斷到阻止Java線程(一個做readLine()調用)。這將導致readLine()調用取消阻止並拋出IOException。不過,也有問題,這種方法:

    • 還有一種情況計時器火災readLine()通話結束後,中斷進入應用程序本身潛在的競爭狀態。這可能會導致問題,這取決於應用程序用中斷執行的操作。您應該能夠避免使用主線程在調用返回時設置的正確同步標誌。

    • 這並不完全清楚,但有跡象表明,如果您在管道上發生中斷,則基礎通道會自動關閉。這意味着你不能要求用戶輸入更多信息。

  • 第二種方法可能與使用NIO通道選擇東西來取代你的BufferedReader/readLine()代碼。除此之外,Selector允許您等待,並通過超時來使通道具有可讀數據。然後你需要在其上實現緩衝和readline。

  • 如果您想知道用戶是否在控制檯中輸入過,則需要將控制檯置於非行編輯模式。這不能在純Java中完成,但有第三方庫可以完成這種功能。

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秒超時內得到有效的響應。

+0

我編輯了我的問題一些更多的細節... 我有一個睡眠的線程,雖然我沒有一個新的消息.. –

+0

我編輯迴應。請首先閱讀關於您的初始問題的評論,看看套接字超時實際上是您需要的。 – Xabster

相關問題