2017-07-07 127 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)'。 (否则,字符编码会因机器,用户和时间而异。) –