在Java中读取C#字节数组

5

我正在使用TCP Socket将文件从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#客户端,代码会在do-while循环中的bytesRead = input.read(...)方法处挂起。
有人知道为什么代码在C#客户端这一点上挂起,而不是Java客户端?根据println消息的输出,数据明确被InputStream接收,并且在bytesRead变量初始化时读取了一次,但在do-while循环期间没有读取。
欢迎提出任何解决此问题的解决方案或建议。
敬礼,
Midavi。

2
展示你的C#代码。你可能忘记了Flush()吗? - dtb
3
如果文件大小不小于或等于有效发送的数据,则read()将阻塞。你永远不应该试图猜测要接收的数据大小,必须持续读取直到流为空。 - Viruzzo
3个回答

1

你需要从C#中以sbyte的形式发送字节,而不是byte

此外,你应该将你的do/while循环改为普通的while循环。如果你在第一次调用input.read时已经读取了流中的所有内容,则在第二次调用时会被阻塞,因为read将等待输入。


那不应该导致它挂起,但在某些时候可能会成为问题。 - user7116
在你解决那个问题之前,由于二进制数据错误,你将无法可靠地解决任何其他问题。 - Charles Lambert
一个有符号字节与一个无符号字节的宽度相同,因此,表示上的差异不会影响从套接字中读取。OP目前的问题在其他地方。 - user7116

0

基于: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循环在确保整个字节数组在重构为文件之前被读取时起到作用。或者我理解错了吗? - midavi

0

由于在一般情况下你无法预先知道发送的数据量,因此最好分块接收数据并忽略大数组中的偏移量。如果数据大于数组或小于数组,则你的代码处理起来不太好。

一个更简单的情况是去掉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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接