通过套接字发送文件 - 缓冲区大小

时间:2017-03-31 19:15:18

标签: java file sockets send

TL; DR:如何发送(使用单个连接)文件,文件大小和名称。互联网上的所有示例都单独发送文件。

服务器:

public class Server {
    private static int PORT = 6667;
    private ServerSocket serverSocket;

    public void run() throws IOException {
        System.out.println("Opening server");
        serverSocket = new ServerSocket(PORT);

        while(true) {
            try(Socket incomingSocket = serverSocket.accept()) {
                System.out.println("Accepted connection: " + incomingSocket);
                incomingSocket.setSoTimeout(2000); // Don't let scanner block the thread.

                InputStream inputStream = incomingSocket.getInputStream();
                Scanner scanner = new Scanner(inputStream);

                String command = "";
                if(scanner.hasNextLine())
                    command = scanner.nextLine();

                if(command.equals("update")) {
                    File file = new File("abc.txt");
                    sendFile(incomingSocket, file);
                }
                else {
                    // ...
                    System.out.println("Another command");
                }
            }
        }
    }

    private void sendFile(Socket socket, File file) throws IOException {
        byte[] bytes = new byte[(int)file.length()];
        FileInputStream fileInputStream = new FileInputStream(file);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        bufferedInputStream.read(bytes, 0, bytes.length);
        OutputStream outputStream = socket.getOutputStream();

        PrintWriter writer = new PrintWriter(outputStream, true);
        writer.println(file.length());
        writer.println(file.getName());

        System.out.println("Sending " + file.getName() + "(" + bytes.length + " bytes) to " + socket);
        outputStream.write(bytes, 0, bytes.length);
        outputStream.flush();
        System.out.println("File sent");
    }

    public void stopRunning() {
        try {
            serverSocket.close();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

客户:

public class Client {
    private static String HOST = "localhost";
    private static int PORT = 6667;

    public void run() throws IOException {
        Socket socket = new Socket(HOST, PORT);
        System.out.println("Connecting...");

        OutputStream outputStream = socket.getOutputStream();
        PrintWriter writer = new PrintWriter(outputStream, true);
        writer.println("update");      // Example command which will determine what server sends back

        receiveFile(socket);

        socket.close();
    }

    private void receiveFile(Socket socket) throws IOException {
        InputStream inputStream = socket.getInputStream();

        int size = 16384;
        String name = "example.txt";

        Scanner scanner = new Scanner(inputStream);
        size = Integer.parseInt(scanner.next());
        name = scanner.next();

        FileOutputStream fileOutputStream = new FileOutputStream(name);
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

        byte[] buffer = new byte[size];
        int bytesRead, totalRead = 0;
        while ((bytesRead = inputStream.read(buffer, 0, buffer.length)) != -1) {
            totalRead += bytesRead;
            bufferedOutputStream.write(buffer, 0, bytesRead);
        }
        bufferedOutputStream.flush();

        System.out.println("File " + name + " received. " + totalRead + " bytes read");

        bufferedOutputStream.close();
        fileOutputStream.close();
    }

我希望我的服务器将文件发送到客户端。它还应包括文件的名称及其大小。名称,因为它非常重要和大小,因为我不想制作一个巨大的硬编码缓冲区。

用上面的代码试了一下。客户的“扫描仪部分”

Scanner scanner = new Scanner(inputStream);
size = Integer.parseInt(scanner.next());
name = scanner.next();

工作正常,但没有收到文件。 inputStream.read(buffer,0,buffer.length)从不从流中读取剩余的字节。

如果我注释掉扫描仪部分,则正确读取字节(大小和名称信息+文件本身)

所以,问题是,如何通过单一连接发送它?或者我应该建立2个单独的连接,第一个请求大小和文件名,并在第二个连接中发送文件?

1 个答案:

答案 0 :(得分:0)

Scanner适用于基于文本的工作。

实现目标的一种方法是使用DataInputStreamDataOutputStream。只需要一个连接:

public void send(File file, OutputStream os) throws IOException {
    DataOutputStream dos = new DataOutputStream(os);

    // writing name
    dos.writeUTF(file.getName());
    // writing length
    dos.writeLong(file.length());

    // writing file content
    ... your write loop, write to dos

    dos.flush();
}

public void receive(InputStream is) throws IOException {
    DataInputStream dis = new DataInputStream(is);

    String fileName = dis.readUTF();
    long fileSize = dis.readLong();

    // reading file content
    ... your read loop, read from dis
}