Сокеты Java: как отправить несколько файлов с клиента на основе события на сервер

#java #sockets

#java #сокеты

Вопрос:

Я пишу программу, в которой клиенту необходимо отслеживать создание файлов в определенной папке и отправлять их по мере их создания на сервер.Сервер всегда должен находиться в режиме прослушивания и сохранять эти файлы с одинаковыми именами в указанной папке на сервере.На данный момент я пытаюсь достичь этого на том же m / c. Как мне достичь этого через сокет?

Я смог отслеживать создание файлов в папке на клиенте и отправлять их.На приемнике я смог получить только один файл.После этого я получал исключение FileNotFoundException на сервере.

Клиентский код

 Socket sock = new Socket("localhost", 5991);  
        System.out.println("Connecting.........");

        Path faxFolder = Paths.get("C:\Users\Tushar Yadav\Music\src\");
        WatchService watchService = FileSystems.getDefault().newWatchService();
        faxFolder.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);

        boolean valid = true;
        do {

            WatchKey watchKey = watchService.take();

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

                    File myFile = new File("C:\Users\Tushar Yadav\Music\src\" fileName);

                    OutputStream os = sock.getOutputStream();  
                    DataOutputStream dos = new DataOutputStream(os);

                    dos.writeUTF(fileName);

                    dos.writeInt((int) myFile.length());

                    int filesize = (int) myFile.length();
                    byte [] buffer = new byte [filesize];

                    Thread.sleep(10000);
                    FileInputStream fis = new FileInputStream(myFile.toString());  
                    BufferedInputStream bis = new BufferedInputStream(fis);  

                    int count; 
                    while ((count = fis.read(buffer)) > 0) {
                        dos.write(buffer, 0, count);
                    }   

                    dos.flush(); 

                }
            }
            valid = watchKey.reset();

        }while (valid);

  

Серверный код

 ServerSocket serverSocket = new ServerSocket(5991);
        Socket clientSocket = null;
        clientSocket = serverSocket.accept();

        in = clientSocket.getInputStream();  
        clientData = new DataInputStream(in); 
        clientBuff = new BufferedInputStream(in); 

        while(true){

            System.out.println("Starting...");  

            String fileName = clientData.readUTF();     

            System.out.println("filename : " fileName);

            int fileSize = clientData.read();

            System.out.println("filesize is " fileSize);

            len=fileSize;

            System.out.println("C:\Users\Tushar Yadav\Music\dest\" fileName);

            output = new FileOutputStream("C:\Users\Tushar Yadav\Music\dest\" fileName);

            dos=new DataOutputStream(output);
            bos=new BufferedOutputStream(output);

            byte[] buffer = new byte[1024];  

            bos.write(buffer, 0, buffer.length); 

            while (len > 0 amp;amp; (smblen = clientData.read(buffer)) > 0) { 
                dos.write(buffer, 0, smblen); 
                len = len - smblen;
                dos.flush();
            }  
            dos.close();  

        }
  

Я ожидаю, что сервер будет ждать, пока клиент отправит другой файл, как только он будет создан на стороне клиента, но я получаю исключение filenotfound вскоре после того, как получатель получил и сохранил первый файл.

Кроме того, одно наблюдение заключается в том, что на стороне сервера я видел, что эта строка System.out.println("filename : " fileName); и последующие строки выполняются дважды, пока не появится исключение, несмотря на создание (и неотъемлемую отправку) только одного файла на клиенте.

Ниже приведены журналы для серверного кода:-

 Starting...
filename : New Text Document.txt
filesize is 0
C:UsersTushar YadavMusicdestNew Text Document.txt
Starting...
filename : 
filesize is 0
C:UsersTushar YadavMusicdest
Exception in thread "main" java.io.FileNotFoundException: C:UsersTushar YadavMusicdest (Access is denied)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(Unknown Source)
    at java.io.FileOutputStream.<init>(Unknown Source)
    at java.io.FileOutputStream.<init>(Unknown Source)
    at test.Server.main(Server.java:55)
  

Ответ №1:

В клиенте вы указываете размер файла с помощью writeInt() , но на сервере вы его считываете с помощью read() . Вы должны использовать readInt() . Это отбросило бы все, поскольку read() считывается только первый байт из 4-байтовой целочисленной длины; затем вы не считываете никаких данных, потому что считаете, что длина равна 0; затем, когда вы пытаетесь прочитать имя 2-го файла, вы теряете позицию и читаете пустую строку, что вызывает ошибку, которую вы видите. Кстати, вероятно, правильнее использовать writeLong() and readLong() , поскольку это возвращаемый тип File.length() , но это зависит от вас, особенно если вы используете только файлы меньшего размера.

Также, кажется, что-то не так с тем, как вы используете DataOutputStream dos и BufferedOutputStream bos , оба из которых заключают в себе одно и то же FileOutputStream output . Сначала вы записываете полный неинициализированный буфер в файл через bos (только часть из которых действительно может быть записана, поскольку она буферизована); затем вы снова считываете и записываете фактические данные файла через dos , которые будут добавлены к тому, что было ранее записано в output . Возможно, вы имели в виду что-то вроде dos = new DataOutputStream(new BufferedOutputStream(output)) , что дало бы вам преимущества обоих. Но вы по-прежнему не хотите записывать весь неинициализированный буфер перед циклом чтения, как вы сделали.

Кроме того, поскольку вы используете только write() , вы, вероятно, могли бы использовать напрямую output.write() без навороченного DataOutputStream. BufferedOutputStream полезен в качестве оптимизации, если вы хотите избежать частых небольших записей на диск, но в этом нет необходимости, тем более что при чтении / записи фрагментов размером 1 КБ существует некоторая внутренняя буферизация.