【问题标题】:Reading a C# byte array in Java在 Java 中读取 C# 字节数组
【发布时间】:2012-01-18 16:50:02
【问题描述】:

我正在使用 TCP 套接字将文件从 C# 客户端传输到 Java 服务器。在 C# 客户端上,我将文件转换为字节数组以进行传输并使用 NetworkStream 发送。

在 Java 服务器上,我使用以下代码将接收到的字节数组转换回文件;

public void run()  {

       try {

            byte[] byteArrayJAR = new byte[filesize];
            InputStream input = socket.getInputStream();

            FileOutputStream fos = new FileOutputStream(
                    "Controller " + controllerNumber + ".jar");

            BufferedOutputStream output = new BufferedOutputStream(fos);

            int bytesRead = input.read(byteArrayJAR, 0, byteArrayJAR.length);
            int currentByte = bytesRead;

            System.out.println("BytesRead = " + bytesRead);

            do {

                bytesRead = input.read(
                        byteArrayJAR,
                        currentByte,
                        (byteArrayJAR.length - currentByte));

                if (bytesRead >= 0) {

                    currentByte += bytesRead;

                }
            }

            while (bytesRead > -1);

            output.write(byteArrayJAR, 0, currentByte);
            output.flush();
            output.close();
            socket.close();

        }

        catch (IOException e) {

            e.printStackTrace();

        }
}

如果接收到的字节数组来自使用 Java 编程的客户端,则上面的代码有效,但对于 C# 客户端,代码在 bytesRead = input.read(...) 方法的 do-while 循环中挂起。

有谁知道为什么此时代码在 C# 客户端而不是 Java 客户端挂起?根据 println 消息的输出,数据肯定会被 InputStream 接收并在 bytesRead 变量初始化时读取一次,但不会在 do-while 循环期间读取。

欢迎任何解决此问题的解决方案或建议。

问候,

米达维。

【问题讨论】:

  • 向我们展示您的 C# 代码。您是否错过了Flush()
  • 如果文件大小不小于或等于有效发送的数据,read() 将阻塞。您永远不要试图猜测您将要接收的数据的大小,您必须继续阅读,直到流为空。

标签: c# java tcp bytearray


【解决方案1】:

您需要从 c# 以 sbyte 而不是 byte 发送字节。

此外,您应该将 do/while 循环更改为常规 while 循环。如果您在第一次调用input.read 时已经读取了流中的所有内容,那么您将在第二次调用时阻塞,因为read 将等待输入。

【讨论】:

  • 这不会导致它挂起,但在某些时候可能会成为问题。
  • 在您解决该问题之前,由于二进制数据错误,您将无法可靠地解决任何其他问题。
  • 有符号字节与无符号字节的宽度相同,因此,表示的差异不会影响从套接字读取。 OP 的 当前 问题在别处。
【解决方案2】:

基于:http://docs.oracle.com/javase/1.4.2/docs/api/java/io/InputStream.html

 int bytesRead = input.read(byteArrayJAR, 0, byteArrayJAR.length);

读取所有可用字节,这意味着您的字节数据已经在 byteArrayJAR 中,或者我在这里完全错了吗?

编辑:

刚刚检查了我的一些项目...我从 Android C# 服务器应用程序发送数据。

我使用String data = input.readLine();(java) 和_sw.WriteLine("Testdata");(C#)

【讨论】:

  • 这也是我所相信的。据我所知,如果要发送的文件相当大,在初始化 bytesRead 后,可能会有更多字节可用。 do-while 循环用于确保在将整个字节数组重建为文件之前读取整个字节数组。还是我错了?
【解决方案3】:

由于在一般情况下您无法知道提前发送的数据量,因此最好以块的形式接收数据并忽略更大数组中的偏移量。如果数据大于您的数组或小于数组,您的代码原样不能很好地处理这种情况。

更简单的情况是删除currentByte 偏移量:

InputStream input = socket.getInputStream();
BufferedOutputStream output = new BufferedOutputStream(
    new FileOutputStream("test.exe"));

byte[] bytes = new byte[2048];
int bytesRead;
do {
    bytesRead = input.read(bytes, 0, bytes.length);
    System.out.println("size: " + bytes.length + " read(): " + bytesRead);

    if (bytesRead > 0) {
        output.write(bytes, 0, bytesRead);
    }
} while (bytesRead > -1);

output.close();
socket.close();
input.close();

我在客户端使用了以下 C# 代码:

if (!args.Any())
{
    Console.Error.WriteLine("Usage: send.exe <executable>");
    Environment.Exit(-1);
}

using (var client = new TcpClient("localhost", 10101))
using (var file = File.Open(args.First(), FileMode.Open, FileAccess.Read))
{
    file.CopyTo(client.GetStream());
}

客户端结果:

C:\temp>csc send.cs
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1
Copyright (C) Microsoft Corporation. All rights reserved.


C:\temp>send send.exe

C:\temp>

服务器端结果:

C:\temp>javac.exe Server.java

C:\temp>java Server
size: 2048 read(): 2048
size: 2048 read(): 2048
size: 2048 read(): 512
size: 2048 read(): -1

C:\temp>test.exe
Usage: send.exe <executable>

【讨论】:

    猜你喜欢
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 2016-06-22
    相关资源
    最近更新 更多