2014-04-07 138 views
0

我正在用Java寫一個簡單的TCP客戶端/服務器程序對,如果客戶端在10秒內沒有發送任何東西,服務器必須斷開連接。 socket.setSoTimeout()讓我,服務器斷開連接就好了。問題是 - 我如何讓客戶端確定服務器是否關閉?目前我使用DataOutputStream來寫入服務器,並且在這裏的一些答案表明,寫入一個封閉的套接字將拋出一個IOException,但是這不會發生。TCP從客戶端檢測斷開的服務器

應該使用什麼樣的編寫器對象將任意字節塊發送到服務器,這會拋出異常或以其他方式指示連接已遠程關閉?

編輯:這是客戶端代碼。這是一個測試功能,它從文件系統讀取一個文件並將其發送到服務器。它以塊的形式發送,並在每個塊之間暫停一段時間。

public static void sendFileWithTimeout(String file, String address, int dataPacketSize, int timeout) { 
    Socket connectionToServer = null; 
    DataOutputStream outStream = null; 
    FileInputStream inStream = null; 
    try { 
     connectionToServer = new Socket(address, 2233); 

     outStream = new DataOutputStream(connectionToServer.getOutputStream()); 

     Path fileObject = Paths.get(file); 

     outStream.writeUTF(fileObject.getFileName().toString()); 

     byte[] data = new byte[dataPacketSize]; 

     inStream = new FileInputStream(fileObject.toFile()); 
     boolean fileFinished = false; 
     while (!fileFinished) { 
      int bytesRead = inStream.read(data); 
      if (bytesRead == -1) { 
       fileFinished = true; 
      } else { 
       outStream.write(data, 0, bytesRead); 
       System.out.println("Thread " + Thread.currentThread().getName() + " wrote " + bytesRead + " bytes."); 
       Thread.sleep(timeout); 
      } 
     } 

    } catch (IOException | InterruptedException e) { 
     System.out.println("Something something."); 
     throw new RuntimeException("Problem sending data to server.", e); 
    } finally { 
     TCPUtil.silentCloseObject(inStream); 
     TCPUtil.silentCloseObject(outStream); 
     TCPUtil.silentCloseObject(connectionToServer); 
    } 
} 

我希望outStream.write在嘗試寫入封閉的服務器時拋出一個IOException,但沒有任何結果。

+0

_「但那不會發生」_。那麼當服務器關閉時會發生什麼? – CHOCKO

+0

您的客戶端輸入流將指示服務器關閉套接字時該流已關閉。如果您碰巧在服務器同時關閉套接字的情況下寫入輸出流,則還應該發生異常。不知道爲什麼你沒有得到例外。你能顯示一些代碼嗎? – anonymous

+0

@CHOCKO - 沒有任何東西。客戶端將數據寫入流並正常退出,而不關心服務器不再存在讀取數據。 – kjerins

回答

-1

請記住ServerSocket.setSoTimeout()與具有相同名稱的客戶端功能不同。

對於服務器來說,這個函數只會拋出SocketTimeoutException讓你捕捉它,如果超時過期,但服務器套接字仍然存在。

對於客戶端,setSoTimeout()涉及流讀取的「讀取超時」。

在你的情況,你必須抓住SocketTimeoutException後顯示關閉連接的插座的服務器代碼=>確保服務器與指定的客戶端關閉了相關的插口。 如果完成,在客戶端,你的代碼行:

throw new RuntimeException("Problem sending data to server.", e);

將被調用。

[更新]

我注意到,你說要設置超時在服務器端接受插座10秒(= 10,000毫秒);那段時間,你的客戶是否完成了所有的文件發送?如果是這樣,則絕不會發生異常。

[推薦]

用於探測,註釋掉你的閱讀文件內容的代碼發送到服務器,並嘗試用幾行寫入輸出流的替換:

outStream.writeUTF("ONE"); 
outStream.writeUTF("TWO"); 
outStream.writeUTF("TREE"); 

然後你可以得出結論。

+0

ServerSocket未關閉 - 它仍然可以與其他潛在客戶端協同工作。服務器的Socket對象(接收來自該特定客戶端的數據的對象)是一個有超時設置的對象,如果沒有收到數據,它將被關閉。 – kjerins

+0

我在服務器接受客戶端連接時提到的套接字是'客戶端套接字'(它相當於客戶端套接字,但具有恢復讀/寫方向)。你如何知道它在服務器端正確關閉? –

+0

這只是更混亂。在ServerSocket上設置超時會導致accept()在超時過期時拋出SocketTimeoutException異常。如果超時過期,在Socket上設置超時會導致讀取方法拋出SocketTimeoutException異常。沒有'read_timeout'這樣的代碼,所以我不知道它爲什麼被格式化爲代碼。他已經表示'服務器斷開連接正常'。客戶端不一定會檢測到服務器關閉:請參閱我的答案。 – EJP

-1

我想你需要刷新關閉你的流寫完後就像outStream.flush(); outStream.close(); inStream.close();

+0

否。close()意味着flush(),並且關閉Socket的輸入或輸出流會關閉另一個流和Socket。 – EJP

0

我希望outStream.write在嘗試寫入封閉的服務器時拋出一個IOException,但什麼都不是。

由於套接字發送緩衝區,第一次不會這樣做。如果你一直在寫,它最終會拋出一個IOException:'連接重置'。如果你沒有數據可以達到這一點,你永遠不會發現對方已經關閉。

+0

這是否適用於所有寫作方法?或者使用DataOutputStream之外的東西解決它? – kjerins

+0

@ user1638190(a)是(b)否。 – EJP

相關問題