通过套接字将图像从android客户端发送到Java服务器时数据丢失

通过套接字将图像从android客户端发送到Java服务器时数据丢失,java,android,sockets,networking,Java,Android,Sockets,Networking,我正在尝试将我的图像从android客户端发送到Java服务器。我发送的图像大小约为99kb,但服务器的读取总是少一些kb,有时为98,有时为96,以此类推。我想知道数据丢失的原因,以及如何以正确的方式发送图像。请帮忙:) 代码: 服务器(接收图像): 编辑 问题已解决,工作代码如下: 客户端: public void sendImage(File file){ try { DataOutputStream out

我正在尝试将我的图像从android客户端发送到Java服务器。我发送的图像大小约为99kb,但服务器的读取总是少一些kb,有时为98,有时为96,以此类推。我想知道数据丢失的原因,以及如何以正确的方式发送图像。请帮忙:)

代码:

服务器(接收图像):

编辑 问题已解决,工作代码如下:

客户端:

        public void sendImage(File file){
             try {
                    DataOutputStream out = new DataOutputStream(
                            socket.getOutputStream());
                    out.writeChar('I');
                    DataInputStream dis = new DataInputStream(new FileInputStream(file));
                    ByteArrayOutputStream ao = new ByteArrayOutputStream();
                    int read = 0;
                    byte[] buf = new byte[1024];
                    while ((read = dis.read(buf)) > -1) {
                        ao.write(buf, 0, read);
                    }

                    out.writeLong(ao.size());
                    out.write(ao.toByteArray());
                    out.flush();
                    out.close();
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
服务器端:

                if(input =='I'){
                    DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
                    long length = dis.readLong();
                    File to = new File("filename.jpg");
                    DataOutputStream dos = new DataOutputStream(
                            new FileOutputStream(to));
                    byte[] buffer = new byte[1024];
                    int len, current = 0;
                    System.out.println(length);
                    while ( current != length) {
                        len = dis.read(buffer);
                        dos.write(buffer, 0, len);
                        current += len;
                        System.out.println(current);
                    }
                    dis.close();
                    dos.close();
                }

作为起点,在客户端,您还需要一个循环来读取本地映像,因为您确定

bis.read(byteArray,0,byteArray.length);

。。。真的在阅读整个图像吗?因此,您还需要一个循环,就像在服务器端一样。

作为起点,在客户端,您还需要一个循环来读取本地映像,因为您确定

bis.read(byteArray,0,byteArray.length);

。。。真的在阅读整个图像吗?因此,您还需要一个服务器端的循环。

根据我个人的经验,PrintWriter和缓冲区不能很好地协同工作。。 作为缓冲区,在您告诉它之前尝试读取数据,它可能会“窃取”不应该这样做的数据。例如,如果您使用任何类型的缓冲读取器来读取服务器端的输入,则缓冲区将在输入图像的“开始”处窃取某些部分,因为它认为这只是另一行。您可以尝试改用DataInputStream和DataOutputStream

客户:

public void sendImage(File file) {
    try {
        DataOutputStream out = new DataOutputStream(
                socket.getOutputStream());
        out.writeChar('I'); // as image,
        DataInputStream dis = new DataInputStream(new FileInputStream(file));
        ByteArrayOutputStream ao = new ByteArrayOutputStream();
        int read = 0;
        byte[] buf = new byte[1024];
        while ((read = dis.read(buf)) > -1) {
            ao.write(buf, 0, read);
        }
        out.writeLong(ao.size());
        out.write(ao.toByteArray());
        out.flush();
        out.close();
        dis.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
服务器:

// assuming folder structure exists.
public void readImage(Socket s, File to) throws IOException {

    DataInputStream dis = new DataInputStream(s.getInputStream());
    char c = dis.readChar();
    if (c == 'I') {
        long length = dis.readLong();
        DataOutputStream dos = new DataOutputStream(
                new FileOutputStream(to));
        byte[] buffer = new byte[1024];
        int len;
        while ((len = dis.read(buffer)) != -1) {
            dos.write(buffer, 0, len);
        }
        dis.close();
        dos.close();
    }

}

根据我个人的经验,PrintWriter和Buffers不能很好地协同工作。。 作为缓冲区,在您告诉它之前尝试读取数据,它可能会“窃取”不应该这样做的数据。例如,如果您使用任何类型的缓冲读取器来读取服务器端的输入,则缓冲区将在输入图像的“开始”处窃取某些部分,因为它认为这只是另一行。您可以尝试改用DataInputStream和DataOutputStream

客户:

public void sendImage(File file) {
    try {
        DataOutputStream out = new DataOutputStream(
                socket.getOutputStream());
        out.writeChar('I'); // as image,
        DataInputStream dis = new DataInputStream(new FileInputStream(file));
        ByteArrayOutputStream ao = new ByteArrayOutputStream();
        int read = 0;
        byte[] buf = new byte[1024];
        while ((read = dis.read(buf)) > -1) {
            ao.write(buf, 0, read);
        }
        out.writeLong(ao.size());
        out.write(ao.toByteArray());
        out.flush();
        out.close();
        dis.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
服务器:

// assuming folder structure exists.
public void readImage(Socket s, File to) throws IOException {

    DataInputStream dis = new DataInputStream(s.getInputStream());
    char c = dis.readChar();
    if (c == 'I') {
        long length = dis.readLong();
        DataOutputStream dos = new DataOutputStream(
                new FileOutputStream(to));
        byte[] buffer = new byte[1024];
        int len;
        while ((len = dis.read(buffer)) != -1) {
            dos.write(buffer, 0, len);
        }
        dis.close();
        dos.close();
    }

}


这可能是服务器写入图像的方式吗?也许会剥离一些元数据或其他什么?随便说说吧……恐怕我不知道。奇怪的是,当我用bitmap.compress方法(但我不想使用bitmap)发送图像时,图像安全到达。我想知道压缩版本是否也会像您的服务器“可能”那样剥离它?我看到您正在读取服务器上的字节数。但你不是在客户机上写这个号码。服务器读取图像的第一部分,并试图将其解释为要接收的数据长度。不,我不这样认为:P图像并没有被真正压缩(我认为它不是:P),因为我设置了100%的质量-类似这样:压缩(Bitmap.CompressFormat.JPG,100,stream)这可能是您的服务器编写图像的方式吗?也许会剥离一些元数据或其他什么?随便说说吧……恐怕我不知道。奇怪的是,当我用bitmap.compress方法(但我不想使用bitmap)发送图像时,图像安全到达。我想知道压缩版本是否也会像您的服务器“可能”那样剥离它?我看到您正在读取服务器上的字节数。但你不是在客户机上写这个号码。服务器读取图像的第一部分,并试图将其解释为要接收的数据长度uhh,不,我不这么认为:P图像并没有被真正压缩(我认为它不是:P),因为我设置了100%的质量-类似这样:压缩(Bitmap.CompressFormat.JPG,100,stream),如lipido所述,read可能不会一次返回所有字节,您需要检查返回的实际大小。如果低于您的要求,请重新阅读。基本上是把整个读取过程放在一个循环中。不幸的是,这与此无关。我已经检查过几次了,客户端的read方法总是返回正确的字节数。然而,您需要一个循环,并且需要在另一端使用相同的循环。read()的约定仅用于传输一个或多个字节。你不能依赖你观察到的行为。正如lipido提到的,read可能不会一次返回所有字节,你需要检查返回的实际大小。如果低于您的要求,请重新阅读。基本上是把整个读取过程放在一个循环中。不幸的是,这与此无关。我已经检查过几次了,客户端的read方法总是返回正确的字节数。然而,您需要一个循环,并且需要在另一端使用相同的循环。read()的约定仅用于传输一个或多个字节。您不能依赖您观察到的行为。您不“信任文件目标存在”。您正在使用“new FileOutputStream()”创建它。您仅假设目录存在。您不“信任文件目标存在”。您正在使用“new FileOutputStream()”创建它。您只是假设目录存在。