简体   繁体   English

通过套接字发送大文件时出错

[英]Error while sending large files through socket

I'm trying to send large files via socket. 我正在尝试通过套接字发送大文件。 The program works fine for small files (such as html pages or pdf), but when i send files over 3/4 mb the output is always corrupted (viewing it with a text editor i noticed that the last few lines are always missing). 该程序适用于较小的文件(例如html页面或pdf),但是当我发送超过3/4 mb的文件时,输出始终会损坏(使用文本编辑器查看它时,我注意到最后几行始终会丢失)。

Here's the code of the server: 这是服务器的代码:

BufferedInputStream in = null;
    FileOutputStream fout = null;
    try {
        server = new ServerSocket(port);

        sock = server.accept();
        in = new BufferedInputStream(sock.getInputStream());

        setPerc(0);

        received = 0;

        int incByte = -1;
        fout = new FileOutputStream(path+name, true);
        long size = length;
        do{
            int buffSize;
            if(size >= 4096){
                buffSize = 4096;
            }else{
                buffSize = 1;
            }
            byte[] o = new byte[buffSize];
            incByte = in.read(o, 0, buffSize);
            fout.write(o);

            received+=buffSize;
            setPerc(calcPerc(received, length));
            size -= buffSize;
            //d("BYTE LETTI => "+incByte);
        }while(size > 0);
        server.close();
    } catch (IOException e) {
        e("Errore nella ricezione file: "+e);
    }finally{
        try {
            fout.flush();
            fout.close();
            in.close();
        } catch (IOException e) {
            e("ERRORE INCOMINGFILE");
        }
    }
    pr.release(port);

And here's the code of the client: 这是客户端的代码:

FileInputStream fin = null;
    BufferedOutputStream out = null;
    try {
        sock = new Socket(host, port);

        fin = new FileInputStream(file);
        out = new BufferedOutputStream(sock.getOutputStream());

        long size = file.length();
        int read = -1;
        do{
            int buffSize = 0;
            if(size >= 4096){
                buffSize = 4096;
            }else{
                buffSize = (int)size;
            }

            byte[] o = new byte[buffSize];
            for(int i = 0; i<o.length;i++){
                o[i] = (byte)0;
            }
            read = fin.read(o, 0, buffSize);
            out.write(o);
            size -= buffSize;
            //d("BYTE LETTI DAL FILE => "+read);
        }while(size > 0);
    } catch (UnknownHostException e) {
    } catch (IOException e) {
        d("ERRORE NELL'INVIO DEL FILE: "+e);
        e.printStackTrace();
    }finally{
        try {
            out.flush();
            out.close();
            fin.close();
        } catch (IOException e) {
            d("Errore nella chiusura dei socket invio");
        }
    }

i think it's something related with the buffer size, but i can't figure out what's wrong here. 我认为这与缓冲区大小有关,但我无法弄清这里出了什么问题。

This is incorrect: 这是不正确的:

        byte[] o = new byte[buffSize];
        incByte = in.read(o, 0, buffSize);
        fout.write(o);

You are reading up to buffSize bytes and then writing exactly buffSize bytes. 您正在阅读最多 buffSize字节,然后写准确 buffSize字节。

You are doing the same thing at the other end as well. 您在另一端也正在做相同的事情。

You may be able to get away with this when reading from a file 1 , but when you read from a socket then a read is liable to give you a partially filled buffer, especially if the writing end can't always keep ahead of the reading end 'cos you are hammering the network with a large transfer. 您可以从文件中读取1时逃脱。但是,当你从一个套接字读那么read容易给你一个部分填充缓冲,特别是如果写到底能不能始终保持阅读的未来最终,因为您正在通过大量传输来锤击网络。

The right way to do it is: 正确的方法是:

        incByte = in.read(o, 0, buffSize);
        fout.write(o, 0, incByte);

1 - It has been observed that when you read from a local file, a read call will typically give you all of the bytes that you requested (subject to the file size, etc). 1-已经观察到,当您从本地文件readread调用通常会为您提供所请求的所有字节(取决于文件大小等)。 So, if you set buffSize to the length of the file, this code would probably work when reading from a local file. 因此,如果将buffSize设置为文件的长度,则从本地文件读取该代码可能会起作用。 But doing this is a bad idea, because you are relying behaviour that is not guaranteed by either Java or a typical operating system. 但这是一个坏主意,因为您所依赖的行为是Java或典型操作系统无法保证的。

You might have a problem eg here. 您可能在这里遇到问题。

read = fin.read(o, 0, buffSize);
out.write(o);

Here read gives you the count of bytes you've actually just read. 在这里, read提供了您实际上刚刚读取的字节数。 On the next line you should write out only as many bytes as you've read. 在下一行,您应该只写出已读取的字节数。

In other words, you cannot expect the size of the file you're reading to be multiple of your buffer size. 换句话说,您不能期望正在读取的文件的大小是缓冲区大小的倍数。

Review your server code too for the same issue. 同样,请检查您的服务器代码。

The correct way to copy streams in Java is as follows: 在Java中复制流的正确方法如下:

while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

where count is an int, and buffer is a byte[] array of length > 0, typically 8k. 其中count是一个int, buffer是一个长度大于0(通常为8k)的byte[]数组。 You don't need to allocate byte arrays inside the loop, and you don't need a byte array of a specific size. 您不需要在循环内分配字节数组,也不需要特定大小的字节数组。 Specifically, it's a complete waste of space to allocate a buffer as large as the file; 具体地说,分配与文件一样大的缓冲区完全浪费了空间。 it only works up to files of Integer.MAX_VALUE bytes, and it doesn't scale. 它仅适用于Integer.MAX_VALUE字节的文件,并且无法缩放。

You do need to save the count returned by 'read()' and use it in the 'write()' method as shown above. 您确实需要保存“ read()”返回的计数,并在“ write()”方法中使用它,如上所示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM