2017-07-07 93 views
-1

我想下面的發送字符串作爲字節數組從C#與Java:通過插座

C#客戶:

string stringToSend = "Hello man"; 
    BinaryWriter writer = new BinaryWriter(mClientSocket.GetStream(),Encoding.UTF8); 

    //write number of bytes: 
    byte[] headerBytes = BitConverter.GetBytes(stringToSend.Length); 
    mClientSocket.GetStream().Write(headerBytes, 0, headerBytes.Length); 
    //write text: 
    byte[] textBytes = System.Text.Encoding.UTF8.GetBytes(stringToSend); 
    writer.Write(textBytes, 0, textBytes.Length); 

Java服務器:

Charset utf8 = Charset.forName("UTF-8"); 
    BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), utf8)); 

    while (true) { 
     //we read header first 
     int headerSize = in.read(); 
     int bytesRead = 0; 
     char[] input = new char[headerSize]; 

     while (bytesRead < headerSize) 
     {  
     bytesRead += in.read(input, bytesRead, headerSize - bytesRead); 
     } 
      String resString = new String(input); 
      System.out.println(resString); 


     if (resString.equals("!$$$")) { 
       break; 
     } 
    } 

字符串大小等於9.這兩個方面都是正確的。但是,當我在Java端讀取字符串iteself時,數據看起來不正確。炭緩衝液( '輸入' 可變)的含量如下:

」, 「」, 'H', 'E', '升', '升', 'O', ''

我試圖通過反轉字節數組來改變字節順序。還試着改變ASCII和UTF-8之間的字符串編碼格式。我仍然覺得它涉及到字節順序問題,但不知道如何解決它。我知道我可以使用其他類型的作家爲了寫入文本數據的蒸汽,但我正在嘗試使用原始字節數組爲了學習。

+0

不可能診斷沒有好的[MCVE]認爲可靠重現問題。但是,看起來在代碼的Java方面,你根本沒有正確讀取字符串長度。 'in.Read()'方法將讀取單個字符,但您需要讀取從C#端發送的整數的四個字節。您不僅應該直接讀取字節(不要將它們解釋爲UTF8字符),您需要讀取正確的數量,然後將其解碼爲32位整數。 –

+0

另外:字節順序不影響ASCII或UTF8。它可能會影響32位整數的傳輸,但你說這很好。所以,endianness似乎不是你的問題。您直接使用'NetworkStream'混合'BinaryWriter',這似乎毫無意義且容易出錯。但我也不認爲這是你的問題。如果修復在Java端讀取的整數不能解決您的問題,請修復問題以便它可以回答。 –

+0

您正在將頭文件長度發送爲來自c#的4字節整數,但只讀取javaside上的單個字節以獲取該值。流中接下來的三個字節是0,0,0,這是java在您輸入時將轉換爲空字符。請參閱下面的答案。 –

回答

2

這些

byte[] headerBytes = BitConverter.GetBytes(stringToSend.Length); 

是4個字節。它們不是字符數據,所以用BufferedReader來讀取它們是沒有意義的。只需直接讀取字節。

byte[] headerBytes = new byte[4]; 
// shortcut, make sure 4 bytes were actually read 
in.read(headerBytes); 

現在提取文本的長度和分配足夠的空間爲它

int length = ByteBuffer.wrap(headerBytes).getInt(); 
byte[] textBytes = new byte[length]; 

然後讀課文

int remaining = length; 
int offset = 0; 
while (remaining > 0) { 
    int count = in.read(textBytes, offset, remaining); 
    if (-1 == count) { 
     // deal with it 
     break; 
    } 
    remaining -= count; 
    offset += count; 
} 

現在爲UTF-8

String text = new String(textBytes, StandardCharsets.UTF_8); 

解碼你就完成了。

字節順序必須匹配那些前4個字節。確保使用「網絡順序」(big-endian)的一種方法。所以:

C#的客戶

byte[] headerBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(stringToSend.Length)); 

Java服務器

int length = ByteBuffer.wrap(headerBytes).order(ByteOrder.BIG_ENDIAN).getInt(); 
+0

是的,就是這樣。現在它變好了。儘管我在C#端使用Array.Reverse來翻轉大端的字節順序。有趣的是,我不必爲字符串部分做這件事。你的endian轉換器行不起作用。HostToNetworkOrder –

+1

@MichaelIvanov沒有匹配的構造函數我認爲Tom剛剛按照調用的順序有一個錯字。現在更正。 –

2

初看起來你的索引有問題。

您的C#代碼正在發送一個整數轉換爲4個字節。

但是你的Java代碼只讀取一個字節作爲字符串的長度。

從C#發送的下一個3字節將從您的字符串長度轉到三個零字節。

您的Java代碼正在讀取這3個零字節並將它們轉換爲空字符,這些空字符表示input []數組的前三個空字符。

C#客戶:

string stringToSend = "Hello man"; 
BinaryWriter writer = new BinaryWriter(mClientSocket.GetStream(),Encoding.UTF8); 

//write number of bytes: Original line was sending the entire string here. Optionally if you string is longer than 255 characters, you'll need to send another data type, perhaps an integer converted to 4 bytes. 
byte[] textBytes = System.Text.Encoding.UTF8.GetBytes(stringToSend); 
mClientSocket.GetStream().Write((byte)textBytes.Length); 
//write text the entire buffer 

writer.Write(textBytes, 0, textBytes.Length); 

Java服務器:

Charset utf8 = Charset.forName("UTF-8"); 
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), utf8)); 

while (true) { 
    //we read header first 
    // original code was sending an integer as 4 bytes but was only reading a single char here. 
    int headerSize = in.read();// read a single byte from the input 
    int bytesRead = 0; 
    char[] input = new char[headerSize]; 

    // no need foe a while statement here: 
    bytesRead = in.read(input, 0, headerSize); 

    // if you are going to use a while statement, then in each loop 
    // you should be processing the input but because it will get overwritten on the next read. 
    String resString = new String(input, utf8); 
    System.out.println(resString); 


    if (resString.equals("!$$$")) { 
     break; 
    } 
} 
+1

'新的字符串(輸入)':我想你的意思是'新的字符串(輸入,utf8)'。 (否則,字符編碼會因機器,用戶和時間而異。) –