2013-11-01 34 views
0

我正在構建一個服務器,在同一時間與幾個客戶端進行通信的Java,我們的初始方法是服務器偵聽來自客戶端的連接,一旦收到一個連接並創建一個套接字,一個新的線程是生成以處理與每個客戶端的通信,即使用ObjectInputStream讀取請求,執行所需的操作(從數據庫獲取數據,更新數據等),並向客戶端發送響應(如果需要)。雖然服務器本身回頭去聽更多的連接。檢查ObjectInputStream是否有無阻塞地讀取的內容?

這對於目前來說很好,但是這種方法並不是真正可擴展的,它對於少量同時連接的客戶端來說效果很好,但是因爲每個客戶端都會產生另一個線程,所以當有一個線程時會發生什麼一次連接的客戶太多?

所以我的下一個想法是維護一個將保存所有連接客戶端(socket對象和一些額外信息)的排序列表,使用ThreadPool遍歷它們並讀取它們發送的任何內容(如果收到消息的話)然後將它放入一個隊列中供另一個工作線程的ThreadPool執行,一旦工作人員完成了它的任務,如果需要響應,就發送它。

後面兩個步驟實現起來相當簡單,問題是每個客戶端實現的原始線程使用ObjectInputStream.readObject()來讀取消息,並且此方法阻塞直到有東西要讀取,對於這種方法來說很好,但是我不能對新方法使用同樣的東西,因爲如果我阻塞了每個套接字,我將永遠不會進入列表中的更深層次。

所以我需要一種方法來檢查,如果我有什麼閱讀之前,我打電話的readObject(),到目前爲止,我嘗試了以下解決方案:

解決方案1: 使用ObjectInputStream.available()來檢查如果有任何可用於讀取的內容,則此方法失敗,因爲此方法似乎始終返回0,無論流中是否存在對象。所以這根本沒有幫助。

解決方案2: 使用PushbackInputStream檢查流中的首個未讀字節的存在,如果它存在,然後將其推回,並閱讀使用ObjectInputStream的對象,如果不繼續前進:

  boolean available; 
      int b = pushbackinput.read(); 
      if (b==-1) 
        available = false; 
      else 
      { 
       pushbackinput.unread(b); 
       available = true; 
      } 
      if (available) 
      { 
      Object message= objectinput.readObject(); 
      // continue with what you need to do with that object 
      } 

事實證明,這也是沒用的,因爲如果沒有輸入來讀取,read()也會被阻塞。它似乎只在流關閉時才返回-1選項。如果流仍然打開,但是它是空的,它只是阻塞,所以這與簡單地使用ObjectInputStream.readObject()並沒有什麼不同。

任何人都可以提出一種方法,實際上會工作嗎?

+2

ObjectInputStream專爲阻止IO而設計。你的問題是,即使有些數據可用,你也不知道如何讀取下一個對象需要的字節。即什麼是有用的量。我會爲每個連接創建一個線程,並且不需要創建自己的線程模型。 –

+0

您可能需要考慮切換到支持返回「Future」之類的讀取方法的NIO通道。 – Gray

+0

使用每個連接的線程阻塞I/O可擴展到數十甚至數十萬個併發客戶端。 – EJP

回答

0

這是一個很好的問題,你已經做了一些家庭作業......但它涉及到通過一些歷史來讓事情正確。請注意,您的問題實際上更多的是使用套接字級通信而不是ObjectInputStream:

過去最簡單的方法是每個套接字都有一個單獨的線程。這是可以擴展到某一點的,但線程很昂貴且創建速度很慢。

作爲響應,對於大型系統,人們創建線程池並在需要完成工作時爲線程上的套接字提供服務。這很複雜。

然後,Java語言隨java.nio包一起更改,該包引入了Selector以及非阻塞IO。這創建了一個可靠的(儘管有時令人困惑)的方式來爲更多的線程服務多個套接字。在你的情況中,它不會完全/很大程度上幫助你,因爲你想知道什麼時候完整的對象已經準備好被讀取,而不是隻有'某個'對象。

在此期間,「風景」發生了變化,Java現在能夠更高效地創建和管理線程。 '現在'的想法是,再次分配每個套接字的單個線程會更好/更快,更容易....參見Java thread per connection model vs NIO

在你的情況,我建議你堅持每個線程模型,你會沒事的。 Java可以擴展和處理比套接字更多的線程,所以你會沒事的。

+0

你知道如何通過NIO通道創建ObjectInputStream嗎? –

+0

請參閱http://stackoverflow.com/questions/1481639/java-serializable-objectinputstream-non-blocking-i-o和http://stackoverflow.com/questions/5862971/java-readobject-with-nio? – rolfl