我正在構建一個服務器,在同一時間與幾個客戶端進行通信的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()並沒有什麼不同。
任何人都可以提出一種方法,實際上會工作嗎?
ObjectInputStream專爲阻止IO而設計。你的問題是,即使有些數據可用,你也不知道如何讀取下一個對象需要的字節。即什麼是有用的量。我會爲每個連接創建一個線程,並且不需要創建自己的線程模型。 –
您可能需要考慮切換到支持返回「Future」之類的讀取方法的NIO通道。 – Gray
使用每個連接的線程阻塞I/O可擴展到數十甚至數十萬個併發客戶端。 – EJP