Java BufferedOutputStream.flush() 不刷新

问题描述 投票:0回答:2

我试图在两端使用 BufferedOutputStream 和 BufferedInputStream 将文件从“服务器”发送到“客户端”。问题是,虽然我在每次写入(右侧)时刷新()服务器上的 BufferedOutputStream,但每刷新一次(左侧),数据就会到达客户端套接字。

正如您所看到的,上面的文件发送得很好,但是如果我使用不同的文件或不同的缓冲区大小,如下所示......

...它“坏了”。客户端上的读取被阻止,因为流中没有任何内容,而且应该有。 这整件事让我很困惑,显然我错过了一些东西。这是我的代码:

客户

import java.io.*;
import java.net.*;
import java.util.Scanner;
import java.lang.Math.*;

/**
 * Client application which allows the user to connect with server
 * and execute simple file transfers.
 *
 */
public class Client
{
    private BufferedReader textFromSocket;
    private PrintWriter textToSocket;
    private BufferedInputStream fileFromSocket;
    private BufferedOutputStream fileToSocket;

    private Socket connection;

    private static final int port = 8888;
    private static final String host = "localhost";
    private static final String filesFolder = "client/clientFiles/";

    /**
     * Initializes all the streams and the socket
     *
     * @throws IOException
     */
    public Client() throws IOException {

            // Try to open up a connection with cslin152, port number 4242. If cslin152 is unavailable,
            // run the this on the same machine as the client, and use the hostname host.
            connection = new Socket( host, port);

            // Buffer the reading stream for performance.
            textFromSocket = new BufferedReader( new InputStreamReader( connection.getInputStream()));

            // Writing stream
            textToSocket = new PrintWriter(
                            new BufferedWriter(
                            new OutputStreamWriter(connection.getOutputStream())), true);

            // Data input (incoming) stream
            fileFromSocket = new BufferedInputStream( new DataInputStream(connection.getInputStream()),8*1024);

            // Data output (outgoing) stream
            fileToSocket = new BufferedOutputStream( new DataOutputStream(connection.getOutputStream()));
    }

    /**
     * Sends a request to server
     *
     * @param cmd request to send
     * @throws IOException
     */
    public void askServer(String cmd) throws IOException {
        if (cmd != null) {
            // write to this
            textToSocket.println(cmd);
        }

        String[] command = cmd.split(" ");
        switch (command[0]) {
            case "list":
                this.readList();
                break;
            case "get":
                if (command.length < 2){
                    System.out.println("Filename not specified");
                }else{
                    this.getFile(command[1]);
                }
                break;
            case "put":
                if (command.length < 2){
                    System.out.println("Filename not specified");
                }else{
                    this.putFile(command[1]);
                }
                break;
            case "bye":
                this.byeBye();
                break;
            default:
                System.out.println(textFromSocket.readLine());
                break;
        }
    }

    /**
     * Executes client-side commands for "list" command
     * "list" command, lists all files available on the server
     */
    public void readList(){
        try {
            String line;
            while ( !(line = textFromSocket.readLine()).equals("")) {
                System.out.println(line);
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Executes client-side commands for "get" command
     * "get" command, downloads a file from server
     *
     * @param filename the name of the file where data will be saved
     */
    public void getFile(String fileName) throws IOException {
        File downloadFile = new File(filesFolder, fileName);
        try (FileOutputStream fos = new FileOutputStream(downloadFile)) {
            copy(fileFromSocket, fos);
            fos.flush();
        }
    }

    public long copy(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[8 * 1024];
        long total = 0L;
        while (true) {
            int read = in.read(buffer);
            if (read < 0) {
                break;
            }
            out.write(buffer, 0, read);
        total += read;
        }
    return total;
    }


    /**
     * Executes client-side commands for "put" command
     * "put" command, uploads a file to server
     *
     * @param filename the name of the file to upload
     */
    public void putFile(String filename){

        File sendFile = new File(filesFolder + filename);
        try {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sendFile));
            int fileSize = (int)sendFile.length();
            if (sendFile.exists()) {
                textToSocket.println(fileSize);
                byte[] myBuffer = new byte[fileSize];
                bis.read(myBuffer, 0, fileSize);
                fileToSocket.write(myBuffer);
                fileToSocket.flush();
                bis.close();
            }else {
                System.out.println("Error: File not found");
            }
        }
        catch (FileNotFoundException e) {
            System.out.println("Error: File doesn't exist");
        }
        catch (IOException e){
            System.out.println("Error: Couldn't read the file");
        }

    }

    /**
     * Closes all the streams, connection and terminates the client
     */
    public void byeBye(){
        try {
            connection.close();
            fileFromSocket.close();
            fileToSocket.close();
            textToSocket.close();
            textFromSocket.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        System.exit(0);
    }

    /**
     * Connects with the server and continuously scans for user input
     *
     */
    public static void main(String[] args)
    {
        Client client = null;
        Scanner keyboardInput = new Scanner(System.in);

        while (client == null){
            try {
                client = new Client();
                System.out.println("Connected to server at : "+ host +":"+ port);
            }
            catch (IOException e) {
                System.out.println("ERROR: Couldn't connect to server, press ENTER to try again");
                // Wait for ENTER
                keyboardInput.nextLine();
            }
        }
        while (true) {
            System.out.printf("client>");
            String cmd = keyboardInput.nextLine();
            try {
                client.askServer(cmd);
            }
            catch (IOException e) {
                System.out.println("Error: Server didn't reply");
            }

        }
    }
}

CLIENT_HANDLER 对于每个线程(连接的客户端)

import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Client handler application which is run as a separate thread for each connected client
 *
 */

public class ClientHandler extends Thread
{
    private BufferedReader textFromSocket;
    private PrintWriter textToSocket;

    private BufferedInputStream fileFromSocket;
    private BufferedOutputStream fileToSocket;

    private Socket connection;

    private static final String filesFolder = "server/serverFiles/";
    private static final String logFile = "server/log.txt";

    /**
     * Initializes all the streams and the socket
     *
     * @throws IOException
     */

    public ClientHandler(Socket client){
        try {
            connection = client;

            // Buffer the reading stream for performance.
            textFromSocket = new BufferedReader( new InputStreamReader( connection.getInputStream()));

            // Writing stream
            textToSocket = new PrintWriter( new BufferedWriter( new OutputStreamWriter(connection.getOutputStream())), true);

            // Data input (incoming) stream
            fileFromSocket = new BufferedInputStream( new DataInputStream(connection.getInputStream()));

            // Data output (outgoing) stream
            fileToSocket = new BufferedOutputStream( new DataOutputStream(connection.getOutputStream()),8*1024);
        }
        catch( IOException e )
        {
            System.out.println( e );
        }
    }

    /**
     * Reads a request from client
     *
     * @return client request
     */

    public String getLine(){
        try {
            return textFromSocket.readLine();
        }
        catch (IOException e) {
            System.out.println("error: Couldn't read from client (Connection Lost)");
            return null;
        }
    }

    /**
     * Executes server-side commands for "list" command
     * "list" command, lists all files available on the server
     */
    public void list(){
        File serverDir = new File(filesFolder);
        File[] fileList = serverDir.listFiles();

        for (int i=0;i<fileList.length;i++){
            textToSocket.println(fileList[i].getName());
        }
        textToSocket.println("");
        textToSocket.flush();
    }

    /**
     * Executes server-side commands for "get" command
     * "get" command, downloads a file from server
     *
     * @param filename the name of the file to be sent to client
     */
    public void get(String filename) throws IOException {
        File fileToSend = new File(filesFolder, filename);
        try (FileInputStream in = new FileInputStream(fileToSend)) {
            copy(in, fileToSocket);
            fileToSocket.flush();
        }
    }

    public long copy(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[8 * 1024];
        long total = 0L;
        while (true) {
            int read = in.read(buffer);
            if (read < 0) {
                break;
            }
            out.write(buffer, 0, read);
        total += read;
        }
    return total;
    }

    /**
     * Executes client-side commands for "put" command
     * "put" command, uploads a file to server
     *
     * @param filename the name of the file to be received from client
     */
    public void put(String filename){
        try{
            String text = textFromSocket.readLine();
            if (text.indexOf("ERROR") == -1) {
                int fileSize = Integer.parseInt(text);
                File downloadFile = new File(filesFolder + filename);
                FileOutputStream fos = new FileOutputStream(downloadFile);

                byte[] myBuffer = new byte[16 * 1024];
                int readBytes = 0;
                int currentBytes = 0;
                while (readBytes < fileSize) {
                    currentBytes = fileFromSocket.read(myBuffer, 0, myBuffer.length);
                    readBytes += currentBytes;
                    fos.write(myBuffer, 0, currentBytes);
                }
                fos.close();
                System.out.println("File downloaded");
            }else{
                System.out.println(text);
            }
        }
        catch (IOException e) {
            System.out.println("ERROR: Couldn't download\\save the file");
        }
    }

    /**
     * Closes all the streams and connection
     */
    public void byeBye(){
        try {
            connection.close();
            fileFromSocket.close();
            fileToSocket.close();
            textToSocket.close();
            textFromSocket.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Stores a request from client in a log.txt file
     * each request is stored in a form: date:time:client IP address:request
     *
     * @param request the request made by client
     */
    public void logRequest(String request){
        File file = new File (logFile);
        try {
            PrintWriter log = new PrintWriter(new BufferedWriter(new FileWriter(file,true)));
            // Get all the details
            Date today = new Date();
            SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy:hh:mm:ss");
            String date = dateFormatter.format(today);
            String address = connection.getInetAddress().toString();
            System.out.println("log: " + date+":"+address+":"+request);
            // Save request with details to file
            log.println(date + ":" + address + ":" + request);
        }
        catch (FileNotFoundException e) {
            System.out.println("error: log.txt couldn't be created");
        }
        catch (IOException e){
            System.out.println("File writer");
        }

    }

    /**
     * Sends an error message to a client
     *
     * @param text content of the message
     */
    public void error(String text){
        textToSocket.println("ERROR Server: "+text);
        textToSocket.flush();
    }

    /**
     * Continuously reads requests from clients and executes them
     */
    public void run() {
        String read;
        while (( read = (this.getLine())) != null) {
            // log the request
            this.logRequest(read);
            // split command for potential arguments
            String[] command = read.split(" ");
            if (command.length > 2) {
                this.error("Too many arguments");
            } else {
                switch (command[0]) {
                    case "list":
                        this.list();
                        break;
                    case "get":
                        if (command.length < 2){
                            System.out.printf("Filename not provided");
                        }else {
                            try {
                                this.get(command[1]);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        break;
                    case "put":
                        if (command.length < 2){
                            System.out.printf("Filename not provided");
                        }else {
                            this.put(command[1]);
                        }
                        break;
                    case "bye":
                        this.byeBye();
                        break;
                    default:
                        this.error("illegal command");
                        break;
                }
            }
        }
    }
}

服务器

import java.net.*;
import java.io.*;
import java.util.concurrent.*;

/**
 * Server application which allows multiple clients to connect and execute simple file transfers.
 *
 * Manages a fixed thread pool of maximum 10 threads (connections)
 *
 */
public class Server {

    private static final int port = 8888;
    // As a demonstration, put everything into main(); obviously you would probably want
    // to use instance variables and break this up into separate methods for a real application.
    public static void main(String[] args) throws IOException {

        ServerSocket server = null;
        ExecutorService service = null;
        File file = new File("server/log.txt");

        // Try to open up the listening port
        try {
            server = new ServerSocket(port);
        }
        catch (IOException e) {
            System.err.println("Could not listen on port: "+ port);
            System.exit(-1);
        }
        System.out.println("Server Running");

        // Initialise the executor.
        service = Executors.newFixedThreadPool(10);

        // Clear/Delete log.txt from last execution
        if (file.exists()){
            if(file.delete()){
                System.out.println("Log cleared");
            }else{
                System.out.println("Log couldn't be cleared");
            }
        }else{
            System.out.println("Log empty, nothing to clear");
        }

        // For each new client, submit a new handler to the thread pool.
        while( true )
        {
            Socket client = server.accept();
            service.submit( new ClientHandler(client) );
            System.out.println("Client connected");
        }
    }

}
java file-transfer java-io flush bufferedoutputstream
2个回答
0
投票

在客户端代码中,您需要在关闭之前调用

fos.flush()

顺便说一句,客户端的最小逻辑并不是真正必要的。有更简单的方法可以实现这些目标。


0
投票

Jags 的两个断言都是正确的,但他们没有写下如何使代码更简单。所以就是这样。这可能是您经常使用的方法,因此请将其放在方便的地方。

public long copy(InputStream in, OutputStream out) throws IOException {
  byte[] buffer = new byte[8 * 1024];
  long total = 0L;
  while (true) {
    int read = in.read(buffer);
    if (read < 0) {
      break;
    }
    out.write(buffer, 0, read);
    total += read;
  }
  return total;
}

那么你的客户端和服务器就会变得非常小:

客户

public void getFile(String filename) throws IOException {
  String text = textFromSocket.readLine(); // Don't
  if (text.contains("ERROR")) {            // know
    return;                                // why
  }                                        // it's
  int fileSize = Integer.parseInt(text);   // needed.
  File downloadFile = new File(filesFolder, fileName);
  try (FileOutputStream fos = new FileOutputStream(downloadFile)) {
    copy(fileFromSocket, fos);
    fos.flush();
  }
}

服务器

public void get(String filename) throws IOException {
  File fileToSend = new File(filesFolder, filename);
  try (FileInputStream in = new FileInputStream(fileToSend)) {
    textToSocket.println(fileToSend.length()); // Not really needed
    copy(in, fileToSocket);
    fileToSocket.flush();
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.