繁体   English   中英

使用Java套接字发送文件,丢失数据

[英]Sending a file with Java Sockets, losing data

我正在尝试将文件从客户端发送到带有Java套接字的服务器。 当我在同一台机器上测试时它工作正常,但是当我在不同的机器上测试时,我丢失了大量数据,导致文件损坏。 如果我尝试发送一个非常小的文件(<20字节),它甚至不会到达服务器的while循环中的println。

这是我的代码:

Server.java

package edu.mst.cs.sensorreceiver;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    private static final int PORT = 51111;
    private static final int CHUNK_SIZE = 1024;
    private static final File _downloadDir = new File("downloads/");

    public static void main(String[] args) {
        if (!_downloadDir.exists()) {
            if (!_downloadDir.mkdirs()) {
                System.err.println("Error: Could not create download directory");
            }
        }

        Socket socket = null;
        try {
            ServerSocket server = new ServerSocket(PORT);

            while (true) {
                System.out.println("Waiting for connection...");
                socket = server.accept();

                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                String name = in.readLine();
                File file = new File(_downloadDir, name);

                String size = in.readLine();
                int fileSize;
                try {
                    fileSize = Integer.parseInt(size);
                } catch (NumberFormatException e) {
                    System.err.println("Error: Malformed file size:" + size);
                    e.printStackTrace();
                    return;
                }

                System.out.println("Saving " + file + " from user... (" + fileSize + " bytes)");
                saveFile(file, socket.getInputStream());
                System.out.println("Finished downloading " + file + " from user.");
                if (file.length() != fileSize) {
                    System.err.println("Error: file incomplete");
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void saveFile(File file, InputStream inStream) {
        FileOutputStream fileOut = null;
        try {
            fileOut = new FileOutputStream(file);

            byte[] buffer = new byte[CHUNK_SIZE];
            int bytesRead;
            int pos = 0;
            while ((bytesRead = inStream.read(buffer, 0, CHUNK_SIZE)) >= 0) {
                pos += bytesRead;
                System.out.println(pos + " bytes (" + bytesRead + " bytes read)");
                fileOut.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOut != null) {
                try {
                    fileOut.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("Finished, filesize = " + file.length());
    }
}

Client.java

package edu.mst.cs.sensorreceiver;

import java.io.*;
import java.net.Socket;

public class Client {
    private static final String HOSTNAME = "131.151.163.153";
    private static final int PORT = 51111;
    private static final int CHUNK_SIZE = 1024;

    public static void main(String[] args) {
        sendFile(args[0]);
    }

    private static void sendFile(String path) {
        if (path == null) {
            throw new NullPointerException("Path is null");
        }

        File file = new File(path);
        Socket socket = null;
        try {
            System.out.println("Connecting to server...");
            socket = new Socket(HOSTNAME, PORT);
            System.out.println("Connected to server at " + socket.getInetAddress());

            PrintStream out = new PrintStream(socket.getOutputStream(), true);

            out.println(file.getName());
            out.println(file.length());

            System.out.println("Sending " + file.getName() + " (" + file.length() + " bytes) to server...");
            writeFile(file, socket.getOutputStream());
            System.out.println("Finished sending " + file.getName() + " to server");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void writeFile(File file, OutputStream outStream) {
        FileInputStream reader = null;
        try {
            reader = new FileInputStream(file);
            byte[] buffer = new byte[CHUNK_SIZE];
            int pos = 0;
            int bytesRead;
            while ((bytesRead = reader.read(buffer, 0, CHUNK_SIZE)) >= 0) {
                outStream.write(buffer, 0, bytesRead);
                outStream.flush();
                pos += bytesRead;
                System.out.println(pos + " bytes (" + bytesRead + " bytes read)");
            }
        } catch (IndexOutOfBoundsException e) {
            System.err.println("Error while reading file");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("Error while writing " + file.toString() + " to output stream");
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

我已经在这方面工作了几个小时,我几乎没有取得任何进展。 我以为我对流的读/写工作有很好的理解,但显然我在这里遗漏了一些东西。

再次,当我从同一台机器发送和接收时,一切都很完美。 但是,如果我尝试在两台计算机之间发送文件,即使两台计算机位于同一个局域网上,我也会丢失很多已发送的数据。

任何人都可以找出我的问题吗? 我已经尝试过我能想到的一切。

您似乎正在混合分块数据和面向行的操作。 我建议你在服务器上使用DataInputStreamDataOutputStream 从客户端开始,类似于

private static void sendFile(String path) {
    if (path == null) {
        throw new NullPointerException("Path is null");
    }

    File file = new File(path);
    Socket socket = null;
    try {
        System.out.println("Connecting to server...");
        socket = new Socket(HOSTNAME, PORT);
        System.out.println("Connected to server at "
                + socket.getInetAddress());

        try (DataOutputStream dos = new DataOutputStream(
                new BufferedOutputStream(socket.getOutputStream()));) {
            dos.writeUTF(file.getName());
            dos.writeLong(file.length());

            System.out.println("Sending " + file.getName() + " ("
                    + file.length() + " bytes) to server...");
            writeFile(file, dos);
            System.out.println("Finished sending " + file.getName()
                    + " to server");
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

然后在服务器上

socket = server.accept();

DataInputStream dis = new DataInputStream(socket.getInputStream());
String name = dis.readUTF();
File file = new File(_downloadDir, name);
long fileSize = dis.readLong();
System.out.println("Saving " + file + " from user... ("
        + fileSize + " bytes)");

在您的代码中,您混合了所有永远不应混合的内容:(a)输入/输出流,(b)PrintStream,(c)流读取器和(d)缓冲读取器。 这种地狱导致了所描述的行为。

你应该使用唯一的对象(流)写你的所有员工。 和唯一的对象(流)阅读所有员工。

我可以建议你使用其中之一

OutputStream out = new BufferedOutputStream(socket.getOutputStream()); // for writing
InputStream in = new BufferedInputStream(socket.getInputStream()); // for reading

要么

DataOutputStream out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

第一种更灵活,第二种更易于使用。

暂无
暂无

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

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