2015-10-15 135 views
0

我有臨危以下類型的消息的網絡套接字:(每秒約24)讀取線和字節[]從輸入流

  • 命令EG:[Pos,1,2,3,4,1,2,3,4]\n

  • 圖片:[IMG,36000]\nbyte[36000] (字節[36000]爲36000個字節的數組)

因此,我需要一個讀卡器該流,其能夠讀取線和字節[]。問題是,BufferedReader轉換字符集,這對圖像來說非常非常糟糕,所以讀取字符串並將其轉換爲字節似乎不是一種選擇。

我試圖將一個DataInputStreamReader和一個BufferedReader連接到流中,但它似乎在讀取器第一次更改後中斷,但我不確定導致該問題的原因。

顯而易見的解決方案是:

char c; 
String s = ""; 
do{ 
    c= (char)read.read(); //maybe charset conversion here 
    s+=c; 
}while(c!= "\n"); 
if(s.startsWith("[IMG")){ 
    int len = Integer.parseInt(s.split(",")[1]); 
    byte[] img = new byte[len]; 
    read.read(img); 
    ... 

但是我正在尋找一個更好的,我需要較少的手動操作。

  • 什麼是處理這個問題的推薦方法?
  • 有沒有方法 連接兩個或更多的讀者到輸入流?
  • 有讀者可以讀取字節[]和字符串?
  • 將所有內容寫入byte []並讀取它可能更容易嗎? (我怎麼知道,什麼時候停止閱讀?)
  • 我可以防止混亂字節[]的圖表類型轉換嗎? (然後我可以使用緩衝閱讀器)

在最簡單的情況下,我可以寫代碼:(這實際上是沒有太大的:d)

String s = read.readLine(); 
String[] parts = s.split(","); 
if(parts[0].equals("[IMG")){ 
    byte[] img = new byte[Integer.parseInt(parts[1])]; 
    read.readByte(img); 
    ... 

回答

0

首先接受所有的二進制數據,使用一個InputStream。

InputStream stream = ... 

,然後在閱讀文字識別時:

int b = stream.read(); 
if (b == (byte)'E') { // Text stream recognized. 
    BufferedReader reader = new BufferedReader(
     new InputStreamReader(stream, charset)); 
    ... use read no longer stream 
} 

您可以創建在一個InputStream一個閱讀器從已經被讀取。 對於控件,您可能會使用單獨的方法並嘗試使用資源。 BufferedInputStream可能會包裝原始InputStream以獲取二進制數據。

+0

問題是,我每秒會收到至少24條這樣的消息,因此即使接受所有消息的部分也變得困難,我仍然需要讀取幀並檢查它們的行結束符,如果它們包含一個,我可以解析該命令,然後讀取指定的長度,並將其餘的緩衝區添加到讀取數據的前面,這是我想要省下的努力。 –

+0

HTTP會有類似Content-Type這樣的空行的標題行,然後是二進制或文本數據。 –

1

更改視點可以提供幫助:將其視爲需要時轉換爲字符串的字節流。在我的情況下,我有一個TCP客戶端/服務器對,它必須處理包含幾個ASCII控制字符(包括CR & LF(= Windows上的java「newline」))的消息 - 並且所有內容都必須按照「原樣」傳遞。

一個字符串可以用來構建一個帶有嵌入式控制代碼的消息,但是嵌入任何「換行」字符(例如,VT)表示不能使用字符串發送或接收消息 - 解決方法是將數據作爲字節傳遞。

繼承人的我做了什麼(在服務器和客戶端)的精髓:

// ASCII control codes 

char SOH = (char) 0x01; 
char STX = (char) 0x02; 
char ETX = (char) 0x03; 

String CRLF = "" + (char) 0x0D + (char) 0x0A; 

int characterCount = 0; 
String characterSet = "US-ASCII"; // "UTF-8", UTF-16", etc. 
String incomingData = ""; 
String outgoingData = ""; 

ServerSocket servSock = new ServerSocket(servPort); 
Socket   clntSock = servSock.accept();     

InputStream incomingData = clntSock.getInputStream(); 
OutputStream outgoingData = clntSock.getOutputStream(); 

while (true) 
{ 
    characterCount = in.read(byteBuffer); // blocks, waiting for remote machine 

    incomingData = new String(byteBuffer, characterSet); // omit 2nd parameter to use default encoding 

    outgoingData = SOH + STX + "Whatever it is" + CRLF + CRLF + CRLF + "you need" + CRLF + "to do" + ETX; 

    byteBuffer = outgoingData.getBytes(CharacterSet); 

    out.write(byteBuffer); 
} 

的盡頭得到什麼被送往(38個字符):SOH + STX + 「不管它是什麼」 + CRLF + CRLF + CRLF +「你需要」+ CRLF +「做」+ ETX

最後一個想法:如果有一種方法/方法來指定I/O包使用的「換行符」有可能:

// My first attempt was for a scanner that is functionally equivalent to System.out but 
// automatically adjusts itself to the SYSTEM-DEPENDENT newline: 
// 
//String LineSeparator  = System.getProperty("line.separator"); 
//String MessageSeparator = Pattern.quote(LineSeparator);  
//Pattern EndOfMessageRegEx = Pattern.compile(MessageSeparator); 

String MessageEndsWith = "" + STX + ETX; // Change this to whatever you need 
String MessageSeparator = Pattern.quote(MessageEndsWith); 
Pattern EndOfMessageRegEx = Pattern.compile(MessageSeparator); 

ServerSocket thisMachine = new ServerSocket(portNumber); 
Socket   otherMachine = thisMachine.accept();  

PrintWriter messageToClient = new PrintWriter(otherMachine.getOutputStream(), true); 

BufferedReader messageFromClient = new BufferedReader( 
       new DataInputStreamReader(otherMachine.getInputStream(), 
              CharacterEncoding)); 
Scanner  ReceivedData = new Scanner(messageFromClient).useDelimiter(EndOfMessageRegEx);