2010-05-07 18 views
1

我爲客戶端 - 服務器應用程序使用Java套接字。有時客戶端需要發送一個字節數組(使用byteArrayOutputStream),有時它應該發送一個自定義Java對象。如何從服務器端的輸入流中讀取信息並確定流中的內容,以便我可以正確處理該信息?Java套接字 - 如何確定服務器端的數據類型?

回答

1

首先將數據讀取到服務器上的字節數組中。編寫你自己的解析例程,只不過是識別字節數組中的內容。

第二步根據第一步的識別執行完整的對象解析。如果解析需要傳遞一個輸入流,那麼您總是可以將您在第一步中讀取的字節數組放入一個新的ByteArrayInputStream實例中。

0

你可以做什麼,將預先發送任何數據與一個整數,用於確定類型。

這樣,您可以讀取前4個字節,然後確定它是什麼類型的數據。

2

總的來說,我不相信Java中有一個功能可以讓你做到這一點。

取而代之的是,考慮發送更多的信息以及解釋接下來會發生什麼類型的每條消息。例如,你可能用一個整數前綴你的消息,這樣每次你收到一條消息時,你會讀取前4個字節(一個整數是4個字節)並解釋它的值(例如1 = byte數組,2 =自定義Java對象,3 =另一個自定義Java對象,...)。

您也可以考慮添加一個包含消息大小的整數,以便知道當前消息何時結束並且下一條消息何時開始。

+1

如果你打算做一個消息開始/結束標誌,這對組成一個轉義協議特別有用,這樣如果你變得不同步,你可以查找消息開始標誌。如果消息開始字節出現在代碼中的任何位置,則將其轉換爲兩字節轉義序列。您還可以逃避轉義字符本身以及您想避免的任何其他字節(^ S和^ Q,例如,通過RS-232使用時)。 – nsayer 2010-05-07 18:51:25

+0

我不會建議開始/結束標誌,因爲在序列化Java類時,因爲在嘗試序列化Java類時可能會發現任何字符(^ S,^ Q,\ 0等)。我建議包括消息的長度和消息的類型。雖然,海報可能已經知道這是基於Java對象的類型(也許對象將始終具有完全相同的字段)。 – 2010-05-07 19:18:23

+0

你做的轉義是爲了確保你的協議完全是二進制安全的,儘管你有特殊的開始/結束標記字節(也許你想完全避免的字節)。如果兩個端點變得不同步,則長度字節不會幫助您恢復,但是,不必承認,您可能不需要擔心TCP連接。 – nsayer 2010-05-07 21:04:22

1

您需要定義一個協議來指出後面的數據類型。例如,您可以使用字符串或枚舉值開始每次傳輸。服務器首先讀取這個數據,然後根據'header'值讀取以下數據。

2

通常這是通過在身體前面發送一個包含身體信息的「標題」來完成的。看看例如HTTP protocol。 HTTP流存在一個由雙換行符與主體分離的頭部。標題依次存在name: value格式的幾個字段,每個字段由一個換行符分隔。在這種特殊情況下,你可以在HTTP中使用Content-Type頭來標識正文的數據類型。

由於Java和TCP/IP沒有爲此提供標準功能,因此您需要指定並記錄您要通過線路詳細發送的格式,以便另一方知道如何處理流。您當然也可以獲取標準規格。例如。 HTTP或FTP。

2

有多種方法可以處理這個問題。

一個是對象序列化,它使用Java的Object(In | Out)putStream發送它。當知道何時從流中讀取對象時,遇到一個小問題。另一個是編組和解組XML。使用更多的流量,但更容易調試和運行。它有助於爲此提供一個良好記錄的XML模式。這裏的優點是可以使用現有的XML庫。

如果需要,您可以嘗試使用自定義格式,但它可能最終只是一個草率的,不太冗長的XML版本。

+1

這裏的關鍵在於作者應該嘗試實現他們自己的對象編組代碼。 – Jason 2010-05-07 19:26:12

+0

@Jason我同意:我想不出任何你想要的理由。 – corsiKa 2010-05-07 19:32:25

2

我會因此而被要求過度殺毒,但除非您認真需要此協議是經濟的,否則您可能會考慮編組數據。我的意思是,在不偷看數據的情況下,通常不能區分是字節數組和其他東西之間的區別,因爲可以想象將所有數據都表示爲字節數組。

您可以非常輕鬆地使用JAXB將數據收集到XML或從XML收集數據。而JAXB甚至會將字節數組對象轉換爲十六進制字符串或Base64。

+0

這是一個巧妙的技巧..但我需要這個儘可能經濟... – markovuksanovic 2010-05-07 18:53:11

0

我認爲最簡單的方法是使用一個對象,其中包含您將隨其類型信息一起發送的數據。然後你可以發送這個對象,根據這個對象的數據類型屬性,你可以提取數據。

相關問題