Сокеты Java - отправка файла и чтение строки не работает - PullRequest
0 голосов
/ 11 декабря 2018

Я пытаюсь отправить список строк с сервера клиенту в сопровождении файлов.Все работало нормально, пока я не реализовал файлы.Теперь происходит отправка файла, сохранение на моем компьютере, затем line = in.readLine() возвращает null', resulting in '!line.equals("DONE"), выдавая ошибку.Еще более странно то, что мой текущий код работает на некоторых компьютерах, а не на других.

Код сервера:

Socket socket = serverSocket.accept();
//Send all map data
System.out.println("Connected");
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
File folder = new File("serverAssets" + File.separator + "dependencies");
File[] listFiles = folder.listFiles();
OutputStream os = socket.getOutputStream();
for (int i = 0; i < listFiles.length; i++) {
    File file = listFiles[i];
    out.println("file" + " " + file.getName() + " " + Long.toString(file.length()));
    String response = in.readLine();
    if (response.equals("READY")) {
        int count;
        byte[] bytes = new byte[(int) file.length()];
        FileInputStream fileIn = new FileInputStream(file);
        BufferedInputStream bufferedIn = new BufferedInputStream(fileIn);
        while ((count = bufferedIn.read(bytes)) > 0) {
            os.write(bytes, 0, count);
        }
        os.flush();
        bufferedIn.close();
    }
}
for (String line : main.mapData) {
    if (line != null || line != "") {
        out.println(line);  
    }
}
out.println("DONE");
socket.close();

Код клиента:

String line = in.readLine();
while (!line.equals("DONE")) {
    String[] splitLine = line.split(" ");
    if (splitLine[0].equals("object")) {
        ...deals with all the different lines of text
    }  else if (splitLine[0].equals("file")) {
        String name = splitLine[1];
        byte[] bytes = new byte[Integer.valueOf(splitLine[2])];
        out.println("READY");
        out.flush();

        InputStream is = socket.getInputStream();
        BufferedOutputStream b = new BufferedOutputStream(new FileOutputStream(name));
        int count;
        int total = 0;
        while ((count = is.read(bytes)) > 0 && total < bytes.length) {
            System.out.println(count);
            total += count;
            b.write(bytes, 0, count);
        }
        b.flush();
        b.close();
        BufferedImage img = ImageIO.read(new File(name));
        Main.images.put(name, img);
    }
    line = in.readLine(); //returns null
}

Вотошибка:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at xyz.krypticcoding.GuaranteeClient.run(GuaranteeClient.java:42)
        at xyz.krypticcoding.Main.connect(Main.java:1102)
        at xyz.krypticcoding.Main$6.actionPerformed(Main.java:934)
        at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
        at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
        at java.awt.Component.processMouseEvent(Unknown Source)
        at javax.swing.JComponent.processMouseEvent(Unknown Source)
        at java.awt.Component.processEvent(Unknown Source)
        at java.awt.Container.processEvent(Unknown Source)
        at java.awt.Component.dispatchEventImpl(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Window.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$500(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)

У меня такое ощущение, что это связано с переключением между потоком и BufferedReader, но я не уверен.

1 Ответ

0 голосов
/ 12 декабря 2018

Ваша самая большая проблема в том, что вы вызываете is.read (в байтах) несколько раз, в то время как байты потенциально могут прочитать весь файл за один раз.Следовательно, повторный вызов не имеет смысла ограничивать число считываемых байтов до фактической длины файла.Следовательно, он читает больше, чем просто отправленный файл, и проглатывает строки, отправленные после файла, тем самым нарушая ваш протокол.На некоторых машинах для достаточно маленьких файлов файл может быть прочитан за один раз, таким образом, не считывая больше байтов, чем ожидалось, и не нарушая ваш протокол.Но это просто случайная встреча.Вы не можете полагаться на это.

Вы должны будете указать read () не читать больше байтов, чем оставшееся число, чтобы прочитать файл.

Не так очевидно, что вы не можете обернутьInputStream или OutputStream из сокета, затем повторно используйте тот же развернутый InputStream или OutputStream.Когда вы это сделаете, это будет работать, пока вы не запустите в угловых случаях, когда он не запускается.

Например, в клиентском коде вы оборачиваете InputStream в BufferedReader для чтения строк, затемв какой-то момент вы используете InputStream напрямую для чтения байтов файлов.Вы не можете сделать это.BufferedReader имеет слабые правила о том, что составляет и конец строки, и будет принимать и использовать самое длинное из \ r, \ n, \ f или \ r \ n.Если сервер работает в странной системе, подобной Mac, и его концы строк имеют вид \ r, но затем вы отправляете файл, в котором первый байт равен \ n, тогда клиент получит \ r с концастроки, затем \ n из файла, и рассмотрите последовательность обоих как фактический конец строки.Таким образом, вы прочитали и использовали первый байт файла, что повредит его начало и заставит вас прочитать еще один байт в конце файла и испортить ваш протокол.Не будет работать.

Подобные проблемы всегда будут существовать, если вы не ожидаете их, если будете использовать объекты InputStream или OutputStream как в обернутом, так и в развернутом виде.Вы не можете сделать это и ожидать, что это будет работать правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...