Клиентское приложение для передачи файлов на основе сокетов Java запускается при отладке, но не работает при нормальном запуске - PullRequest
1 голос
/ 17 октября 2019

Мне было дано задание создать Dropbox, как приложение для передачи файлов с несколькими клиентами на одном клиенте. Поэтому я создал серверное приложение на Java, которое работает непрерывно, чтобы принимать соединения от клиентов и давать каждому клиенту свой собственный поток, чтобы они могли работать одновременно. Клиенты, с другой стороны, отслеживают заранее определенную папку для любых новых файловых добавлений. Как только они обнаруживают новый файл, они отправляют его на сервер. Когда сервер получает файл, он отправляет этот файл всем подключенным клиентам.

Моя проблема в том, что код клиента работает нормально во время отладки, но при нормальном запуске выдает ошибку: Ошибка: java.io.FileNotFoundException: D: \ Distributed Systems \ Labs \ Lab_1 \ client_1 \ shared_directory \ random.txt (процесс не может получить доступ к файлу, потому что он используется другим процессом)

после некоторой отладки я понял, что эта ошибка происходитпотому что клиентский код слишком быстрый, и поэтому мне пришлось искусственно замедлять его, добавляя Thread.sleep ().

Что можно сделать, чтобы клиент ожидал правильного добавления файла вотслеживаемая папка перед тем, как пытаться отправить ее на сервер?.

Я использую java.nio.file Watch Service API для отслеживания папки на наличие новых или измененных файлов.

Код услуги:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class FT_Server {

    // Vector to store active clients
    static Vector<ClientHandler> connectedClients = new Vector<>();
    static ArrayList<String> clientNames = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        String userName = "";

        try (ServerSocket serverSocket = new ServerSocket(59898)) {
            System.out.println("Server is running, waiting for connection");

            ExecutorService pool = Executors.newFixedThreadPool(20);

            while (true) {
                //client socket created
                Socket clientSocket = serverSocket.accept();

                //obtain input and output streams
                DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
                DataOutputStream dos = new DataOutputStream(clientSocket.getOutputStream());

                userName = dis.readUTF();

                System.out.println(userName);

                // check if username already exists

                for (ClientHandler clt : FT_Server.connectedClients) {
                    clientNames.add(clt.cltName);
                }

                while (clientNames.contains(userName)) {
                    dos.writeUTF("FALSE");
                    userName = dis.readUTF();
                }

                dos.writeUTF("TRUE");

                System.out.println("Creating a new handler for this client...");

                // Create a new handler object for handling this request.
                ClientHandler clt = new ClientHandler(clientSocket, userName);

                //add the new client handler object to the vector of connected clients
                connectedClients.add(clt);
                clientNames.add(userName);

                System.out.println(connectedClients);
                System.out.println(clientNames);

                pool.execute(clt);
            }
        } catch(IOException ioe){
            ioe.printStackTrace();
        }
    }
}

class ClientHandler implements Runnable {
    DataInputStream  dis       = null;
    DataOutputStream dos       = null;
    FileOutputStream fos = null;
    Socket           cltSocket;
    String           cltName;
    FileInputStream fis = null;
    BufferedInputStream bis = null;
    InputStream in = null;
    boolean isloggedin;

    ClientHandler(Socket clientSocket, String userName) {
        this.cltSocket = clientSocket;
        this.cltName = userName;
        this.isloggedin=true;
    }

    @Override
    public void run() {
        System.out.println("inside ClientHandler class's run method");
        String fileName = "";
        int bytesRead = 0;

        while (true){
            try {
                // receive file from client
                dis = new DataInputStream(cltSocket.getInputStream());
                dos = new DataOutputStream(cltSocket.getOutputStream());

                if (dis != null)
                    System.out.println("dis not null");

                //get the name of the file
                fileName = dis.readUTF();
                System.out.println("fileName = "+fileName);

                if(fileName.equals("logout")){
                    this.isloggedin=false;
                    this.cltSocket.close();
                    break;
                }

                fos = new FileOutputStream("D:/Distributed Systems/Labs/Lab_1/server/" + fileName);

                //get the size of the file to be received
                long size = dis.readLong();
                System.out.println("size = "+size);

                byte[] buffer = new byte[(int) size];

                //write the data bytes received to a file
                while (size > 0 && (bytesRead = dis.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) {
                    fos.write(buffer, 0, bytesRead);
                    size -= bytesRead;
                }

                System.out.println("File " + fileName + " downloaded from client(" + size + " bytes read)");

            } catch (IOException e1) {
                e1.printStackTrace();
            }

            //send the file to all the connected clients
            final String FILE_TO_SEND = "D:/Distributed Systems/Labs/Lab_1/server/" + fileName;

            try {
                System.out.println("inside sending file to connected clients try section");
                File myFile = new File(FILE_TO_SEND);
                byte[] fileContents = new byte[(int) myFile.length()];

                fis = new FileInputStream(myFile);
                bis = new BufferedInputStream(fis);
                // disB = new DataInputStream(bis);

                if (bis != null){
                    System.out.println("bis not null");
                }

                //fill the data into the Byte array?
                bis.read(fileContents, 0, fileContents.length);

                // Sending file to each connected client
                for (ClientHandler clt : FT_Server.connectedClients) {
                    System.out.println("inside for loop");
                    if (clt.cltName != this.cltName && clt.isloggedin==true){
                        System.out.println("inside if");
                        //Send the file name to the client
                        clt.dos.writeUTF(myFile.getName());

                        //send the length of the file to the client
                        clt.dos.writeLong(fileContents.length);

                        System.out.println("Sending the file" + FILE_TO_SEND + "(" + fileContents.length + " bytes)");

                        //send the file contents to the client?
                        clt.dos.write(fileContents, 0, fileContents.length);
                        clt.dos.flush();

                        // // Sending file data to the client?
                        // os.write(fileContents, 0, fileContents.length);
                        // os.flush();
                        System.out.println("File sent to client = "+clt.cltName);
                    }
                }
            } catch (Exception e) {
                System.out.println("Error: " + e + "for client socket: " + cltSocket);
            }
        }
        try {
            System.out.println("inside finally");
            dis.close();
            dos.close();
            fos.close();
            fis.close();
            bis.close();
            cltSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Код клиента:

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.file.*;
import java.util.Scanner;

public class FT_Client_1 {
    Socket clientSocket = null;
    DataInputStream dis = null;
    DataOutputStream dos = null;

    public static void main(String[] args) throws Exception {

        FT_Client_1 clt = new FT_Client_1();

        clt.startConnection();

        clt.runClient();

//        clt.closeConnection();
    }

    public void runClient() {
        System.out.println("inside runClient()");
        //monitor the shared directory and send any new files to the server
        MonitorSharedDirectory mon = new MonitorSharedDirectory();
        Thread t1 = new Thread(mon);
        t1.start();

        // Receive any files sent by the server
        receiveFileFromServer rec = new receiveFileFromServer();
        Thread t2 = new Thread(rec);
        t2.start();
    }

    public void startConnection() throws UnknownHostException, IOException {
        System.out.println("inside startConnection()");
        String username = "";
        Boolean valid = true;

        // taking username as input from the user
        Scanner sc = new Scanner(System.in);

        System.out.println("Enter a username:");
        username = sc.nextLine();

        //creating client socket
        clientSocket = new Socket("127.0.0.1", 59898);

        //getting the data input and output stream using client socket
        dos = new DataOutputStream(clientSocket.getOutputStream());
        dis = new DataInputStream(clientSocket.getInputStream());

        dos.writeUTF(username);
        System.out.println("after sending username to the server");

        // Checking if server accepted the username
        do {
            String serverReply = dis.readUTF();
            if (serverReply == "FALSE"){
                // disconnect from server socket TODO
                System.out.println("Given Username is already in use, please provide another Username");
                username = sc.nextLine();
                dos.writeUTF(username);
            }else {
                valid = false;
            }
        }while (valid);

        System.out.println("after while loop to check if username is unique");
        sc.close();
        System.out.println("client " + username + " has been connected to the server");
    }

    public class MonitorSharedDirectory implements Runnable {
        FileInputStream fis = null;
        BufferedInputStream bis = null;

        @Override
        public void run() {
            System.out.println("inside MonitorSharedDirectory class's run method");

            try{
                System.out.println("inside MonitorSharedDirectory try section");

                Path watchFolder = Paths.get("D:/Distributed Systems/Labs/Lab_1/client_1/shared_directory/");
                WatchService watchService = FileSystems.getDefault().newWatchService();
                watchFolder.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY); //add ENTRY_MODIFY to this to monitor for file modifications

                boolean valid = true;

                do {
                    WatchKey watchKey = watchService.take();

                    for (WatchEvent event : watchKey.pollEvents()) {

                        WatchEvent.Kind kind = event.kind();
                        if (StandardWatchEventKinds.ENTRY_CREATE.equals(kind) || StandardWatchEventKinds.ENTRY_MODIFY.equals(kind)) {
                            String fileName = event.context().toString();
                            System.out.println("File Created:" + fileName);

                            int attempts = 0;
                            while(dis.available() == 0 && attempts < 1000)
                            {
                                attempts++;
                                Thread.sleep(5);
                            }

                            // sending new file to server
                            File myFile = new File("D:/Distributed Systems/Labs/Lab_1/client_1/shared_directory/" + fileName);
                            byte[] fileContents = new byte[(int) myFile.length()];

                            fis = new FileInputStream(myFile);
                            bis = new BufferedInputStream(fis);
                            DataInputStream dis = new DataInputStream(bis);

                            dis.readFully(fileContents, 0, fileContents.length);

                            dos.writeUTF(myFile.getName());
                            dos.writeLong(fileContents.length);
                            dos.write(fileContents, 0, fileContents.length);
                            dos.flush();
                            System.out.println("File "+fileName+" sent to Server.");


//                            //fill the data into the Byte array?
//                            bis.read(fileContents, 0, fileContents.length);
//
//                            dos.writeUTF(myFile.getName());
//
//                            //send the length of the file to the client
//                            dos.writeLong(fileContents.length);
//
//                            System.out.println("Sending the file " + myFile + " (" + fileContents.length + " bytes)");
//
//                            //send the file contents to the server?
//                            dos.write(fileContents, 0, fileContents.length);
//                            dos.flush();

                            if (fis != null)
                                fis.close();
                            if (bis != null)
                                bis.close();
                            if (dis != null)
                                dis.close();
                        }
                    }
                    valid = watchKey.reset();
                } while (valid);
            }catch(Exception e){
                System.out.println("Error Prem: " + e );
            }finally {
                //if (dos != null)
                //dos.close();
                try {
                    if (fis != null)
                        fis.close();
                    if (bis != null)
                        bis.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

    public class receiveFileFromServer implements Runnable {
        FileOutputStream fos = null;

        @Override
        public void run() {
            System.out.println("inside receiveFileFromServer class's run method");

            while (true){
                try {
                    System.out.println("inside receiveFileFromServer try section");

                    // receive file from server
                    String fileName = dis.readUTF();

                    System.out.println(fileName);

                    fos = new FileOutputStream("D:/Distributed Systems/Labs/Lab_1/client_1/shared_directory/" + fileName);

                    int bytesRead = 0;

                    long size = dis.readLong();

                    byte[] buffer = new byte[(int) size];

                    while (size > 0 && (bytesRead = dis.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) {
                        fos.write(buffer, 0, bytesRead);
                        size -= bytesRead;
                    }
                    System.out.println("File " + fileName + " downloaded from server(" + size + " bytes read)");

                    if (fos != null)
                        fos.close();

                } catch (Exception e) {
                    System.out.println("Error: " + e);
                    e.printStackTrace();
                }
            }
        }
    }

    public void closeConnection() throws IOException {
        System.out.println("inside closeConnection()");
        if (dis != null)
            dis.close();
        if (dos != null)
            dos.close();
        if (clientSocket != null)
            clientSocket.close();
    }
}

Ответы [ 2 ]

0 голосов
/ 18 октября 2019

простой подход - вы можете справиться с этим, храня регистр файлов в маленьком дБ на сервере с отметкой и размером файла, который мы называем метаданными.

Таким образом, если файл будет изменен в будущем иотправлено во второй раз с измененным содержимым, вы можете посмотреть метаданные.

Если тот же файл отправлен на сервер, сервер отклоняет файл и не будет распространяться на другие клиенты.

В моем случае я использовал aws sqs и просматривал идентификаторы сообщений для проверки дубликатов файлов.

Надеюсь, этот подход поможет.

0 голосов
/ 17 октября 2019

Я столкнулся с точно такой же проблемой при написании инвентарного приложения с наблюдателем и созданием события. скорее добавляя нить сна и счетчик в цикле, я бы посмотрел размер файла, если он будет продолжать меняться. Для этого есть код в Google. Это работает как шарм.

...