Запрос определенного файла с сервера через сокет в java

#java #sockets #file-transfer

#java #сокеты #передача файла

Вопрос:

Я нашел некоторый код, который передает файлы между клиентом и сервером. Но расположение файла и номера портов жестко запрограммированы. Мне было интересно, есть ли способ, которым клиент может указать, какой файл ему / ей нужен с сервера, — чтобы, когда сервер получит запрос, он мог отправить этот конкретный файл клиенту. Спасибо.


Редактировать [1]: фрагмент кода и описание контекста:

Я добавляю код, который у меня есть на данный момент, на основе отзывов и комментариев. Надеюсь, это ответит на некоторые вопросы в разделе комментариев.

 import java.net.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Original coder adapted from:
 * http://www.rgagnon.com/javadetails/java-0542.html
 *
 * Best intentions:
 * This program runs both as server and client.
 * 
 * The client asks for a specific file from _
 * the server x number of times in a loop.
 * 
 * Server simply serves the file requested.
 */

public class FileServer extends Thread {

    public static void server() throws IOException {
        ServerSocket servsock = new ServerSocket(13267);
        while (true) {
            System.out.println("Waiting...");

            Socket sock = servsock.accept();
            System.out.println("Accepted connection : "   sock);

            //Retrieve filename to serve
            InputStream is = sock.getInputStream();
            BufferedReader bfr = new BufferedReader(new InputStreamReader(is));
            String fileName = bfr.readLine();
            bfr.close();

            System.out.println("Server side got the file name:"   fileName);

            //Sendfile
            File myFile = new File(fileName);
            byte[] mybytearray = new byte[(int) myFile.length()];
            FileInputStream fis = new FileInputStream(myFile);
            BufferedInputStream bis = new BufferedInputStream(fis);
            bis.read(mybytearray, 0, mybytearray.length);
            OutputStream os = sock.getOutputStream();
            System.out.println("Sending...");
            os.write(mybytearray, 0, mybytearray.length);
            os.flush();
            sock.close();
        }
    }

    public static void client(int index) throws IOException {
        int filesize = 6022386; // filesize temporary hardcoded

        long start = System.currentTimeMillis();
        int bytesRead;
        int current = 0;
        //Localhost for testing
        Socket sock = new Socket("127.0.0.1", 13267);

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

        //Ask for specific file: source1
        String fileName = "source1";
        OutputStream os = sock.getOutputStream();
        PrintWriter pw = new PrintWriter(os);
        pw.println(fileName);


        //Receive file
        byte[] mybytearray = new byte[filesize];
        InputStream is = sock.getInputStream();
        FileOutputStream fos = new FileOutputStream("source1-copy"   index);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        bytesRead = is.read(mybytearray, 0, mybytearray.length);
        current = bytesRead;

        // thanks to A. Cádiz for the bug fix
        do {
            bytesRead =
                    is.read(mybytearray, 
                            current, (mybytearray.length - current));
            if (bytesRead >= 0) {
                current  = bytesRead;
            }
        } while (bytesRead > -1);

        bos.write(mybytearray, 0, current);
        bos.flush();

        long end = System.currentTimeMillis();
        System.out.println(end - start);
        os.flush();

        bos.close();
        sock.close();
    }

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

        FileServer fs = new FileServer();
        fs.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(
                   FileServer.class.getName()).log(Level.SEVERE, null, ex);
        }

        for (int i = 0; i < 5; i  ) {
            client(i);
        }

    }

    @Override
    public void run() {
        try {
            server();
        } catch (IOException ex) {
            Logger.getLogger(
                   FileServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
  

Когда я запускаю этот код, он застревает в строке «Подключение …». Вот результат:

Ожидание…
Принятое соединение: сокет [addr=/127.0.0.1, порт =44939,localport=13267]
Подключается…

Комментарии:

1. О каком протоколе вы говорите? HTTP? FTP?

2. Просто используйте один из стандартизированных протоколов копирования файлов, таких как scp, http или (shudder) ftp.

3. Вы, безусловно, запрашиваете определенный файл при выполнении HTTP-запроса (я предполагаю, что это то, о чем вы говорите). Что сервер делает с этим запросом и его параметрами, зависит от вашей конфигурации.

4. Если найденный вами код жестко запрограммирован для использования определенных местоположений файлов и портов, то, похоже, решение состоит в том, чтобы просто сделать так, чтобы это был параметр в запросе. Другими словами… удалите жесткое кодирование.

5. Возможно, BackOrifice делает то, что вы хотите.

Ответ №1:

@moejoe Я думаю, ты слишком много думаешь об этом.

Если у вас уже есть возможность отправить файл, то первое, что нужно сделать, это абстрагировать эту функциональность, чтобы вы могли запустить ее как метод и указать путь / filename.

Затем вы можете использовать сокет (который является двусторонним) для отправки сообщения от клиента на сервер с запросом, какой файл вы хотите. Помимо этого, вопрос в том, как получить нужный файл из пользовательского интерфейса. Возможно, вам потребуется, чтобы сервер предоставил метод «список доступных файлов», то есть функциональность ls.

Все это довольно тривиально для реализации.

Комментарии:

1. @glowcoder Я думаю, вы правы. Я изменил свой код на основе вашего предложения, но теперь у меня новая проблема. Пожалуйста, посмотрите мои правки. Спасибо.

2. @moejoe Лично я бы не стал отправлять байты от клиента к серверу. Я бы просто отправил сообщение в виде строки — так проще анализировать и с ним работать. Оберните ваш OutputStream в PrintWriter и используйте new BufferedReader(new InputStreamReader(sock.getInputStream()) . Затем в клиенте вы можете сделать pw.println(filename); , а на вашем сервере перейти String filename = br.readLine();

3. @glowcoder Я внес изменения, но проблема все еще сохраняется. Код застревает при «Подключении …», как я упоминал в своей правке. Я предполагаю, что это проблема с тем, как я создаю поток?

4. @glowcoder Имя файла не считывается на стороне сервера — я только что проверил — я сомневаюсь, что клиент вообще может отправить имя файла через.

5. Согласно коду в вашем сообщении прямо сейчас… Ваш сервер использует readLine() , но ваш клиент не передает строку. На самом деле это никогда не заканчивается строка. Что касается сервера, он все еще читает частично завершенную строку. Если вы измените клиентскую часть (только) на использование PrintWriter и use println(filename) , он должен появиться на сервере.