通过套接字将字符串作为字节数组从C#发送到Java

时间:2017-07-07 23:12:15

标签: java c#

我正在尝试以下方法:

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 Server:

   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时,数据看起来是错误的。字符缓冲区('input'变量)内容如下所示:

  

”, “”, 'H', 'E', '升', '升', 'O', ''

我试图通过反转字节数组来改变字节顺序。也尝试在ASCII和UTF-8之间改变字符串编码格式。我仍觉得它与字节序问题有关,但无法弄清楚如何解决它。我知道我可以使用其他类型的编写器来将文本数据写入steam,但我正在尝试使用原始字节数组来学习。

2 个答案:

答案 0 :(得分:2)

乍一看,您的索引似乎有问题。

您的C#代码正在发送转换为4个字节的整数。

但是你的Java代码只读取一个字节作为字符串的长度。

从C#发送的接下来的3个字节将从字符串长度转到三个零字节。

您的Java代码正在读取这3个零字节并将它们转换为空字符,这些字符代表input []数组的前3个空字符。

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 Server:

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 :(得分: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);

你完成了。

Endianness必须与前4个字节匹配。确保使用“网络订单”(big-endian)的一种方法。所以:

C#客户端

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

Java Server

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