Java Конец Исключения Файла - PullRequest
0 голосов
/ 10 ноября 2019

Я пишу простую программу обмена мгновенными сообщениями с использованием JavaFX и обнаружил исключение End Of File, и после нескольких часов отладки я не могу найти решение.

Моя программа состоит из двух частей: клиента исервер. Они посылают друг другу сериализованные объекты, содержащие всю необходимую информацию для выполнения требуемого действия. Я добавил дополнительные функции в свою программу, когда начал получать эту ошибку на сервере. С тех пор я удалил весь дополнительный код, но все еще получаю это сообщение об ошибке. Я не понимаю, почему я получаю эту ошибку, так как ни клиент, ни сервер не отправляют сообщение, означающее, что нет файла для достижения конца ??

Я закомментирую строку, где я вызываю метод«sendMessage ()», и это, кажется, решает проблему, но мне нужен этот метод для работы.

Ниже приведена копия класса сервера

package instachatfx.server;


public class ServerMain {

    private static HashSet<ObjectOutputStream> writers;
    private static ArrayList<User> users = new ArrayList<>();

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        writers = new HashSet<>();

        try (ServerSocket listener = new ServerSocket(Constants.
            while (true) {
                new Handler(listener.accept()).start();
            }
        } catch (IOException ex) {
            Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private static class Handler extends Thread {

        private Socket socket;

        private ObjectInputStream input;
        private OutputStream os;
        private ObjectOutputStream output;
        private InputStream is;

        private User user;
        private String code;

        public Handler(Socket socket) throws IOException {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                is = socket.getInputStream();
                input = new ObjectInputStream(is);
                os = socket.getOutputStream();
                output = new ObjectOutputStream(os);

                while (socket.isConnected()) {
                    System.out.println("Waiting for packet...");
                    Packet inputmsg = (Packet) input.readObject();
                    if (inputmsg != null) {
                        switch (inputmsg.getHeader()) {
                            case REGISTER:
                                System.out.println("Case: REGISTER");
                                registerUser((User) inputmsg.getContent());
                                break;
                            case LOGIN:
                                System.out.println("Case: LOGIN");
                                loginUser((User) inputmsg.getContent());
                                break;
                            case CODE:
                                System.out.println("Case: CODE");
                                if (((String) inputmsg.getContent()).equalsIgnoreCase(code)) {
                                    Constants.getDBManager().createNewUser(user);
                                    loginUser(user);
                                } else {
                                    sendMessage(PacketHeader.INCORRECT_CODE, "Incorrect code");
                                }
                                break;
                            case MESSAGE:
                                System.out.println("Case: MESSAGE");
                                sendToAll(inputmsg);

                                System.out.println(((Message) inputmsg.getContent()).getUser().toString() + ": " + ((Message) inputmsg.getContent()).getContent());
                                break;
                            default:
                                throw new HeaderNotFoundException("Server has no case for: " + inputmsg.getHeader().name());
                        }
                    }
                }
            } catch (SocketException ex) {
                Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
            } catch (HeaderNotFoundException ex) {
                Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
            } catch (EOFException ex)
                Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                closeConnections();
            }

        }

        private void sendToAll(Packet msg) throws IOException {
            System.out.println("Send to all: " + msg.getHeader());
            ((Message) msg.getContent()).setUsers(users);
            for (ObjectOutputStream writer : writers) {
                writer.writeObject(msg);
                writer.flush();
                writer.reset();
            }
        }

        private void sendToOthers(Packet msg) throws IOException {
            System.out.println("Send to others: " + msg.getHeader());
            ((Message) msg.getContent()).setUsers(users);
            for (ObjectOutputStream writer : writers) {
                if (output != writer) {
                    writer.writeObject(msg);
                    writer.flush();
                    writer.reset();
                }
            }
        }

        /**
         * Logs in a user
         * @param u the user to be logged in
         */
        private void loginUser(User u) {
            try {
                User us;
                if ((us = Constants.getDBManager().loginUser(u)) != null) {
                    System.out.println("User found in database");
                    user = us;
                    writers.add(output);
                    users.add(user);
                    LoginMsg msg = new LoginMsg(user, users);
                    sendMessage(PacketHeader.LOGIN_SUCCESSFUL, 
                    sendToOthers(new Packet(PacketHeader.MESSAGE, new Message(user.toString() + " has joined the chat", new User("SERVER", null))));
                } else {
                    sendMessage(PacketHeader.LOGIN_FAIL, "Please check email and password");
                }
            } catch (IOException ex) {
                Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        private void registerUser(User u) throws IOException{
            user = u;
            if (Constants.getDBManager().checkDeuplicateEmail(u.getEmail())) {
                sendMessage(PacketHeader.EMAIL_ALREADY_USED, "The email address " + u.getEmail() + " has already been used to make an account");
                System.out.println("Email already exists");
                return;
            } else if ((code = sendVerificationEmail(u)) == null) {
                sendMessage(PacketHeader.EMAIL_NOT_VALID, "There was an error sending the email  to "
                        + u.getEmail() + ". Please make sure the email is correct");
                System.out.println("email failed sending");
                return;
            }

            sendMessage(PacketHeader.WAIT_FOR_CODE, "Type in code in email");
        }

        /**
         * Sends an email to the user to verify that it is correct
         *
         * @param u The user to send the email to
         * @return null - the email failed sending <br>
         * random sting - the email successfully sent using this verification
         * code
         */
        private String sendVerificationEmail(User u) {
            String code = RandomString.getAlphaNumericString(10);
            if (Constants.getSendEmail().sendEmail(u, code)) {
                return code;
            }

            return null;
        }

        /**
         * Sends a packet to only the client
         *
         * @param packetHeader for the client to tell how to read in the message
         * @param msg the message for the client
         */
        private void sendMessage(PacketHeader packetHeader, Object msg) throws IOException {
            System.out.println("Send to client: " + packetHeader);
            Packet message = new Packet(packetHeader, msg);
            //ERROR OCCURS HERE
            output.writeObject(message);
            output.flush();
        }

        private void closeConnections() {
            if (user != null){
                users.remove(user);
            }

            try {
                sendToAll(new Packet(PacketHeader.MESSAGE, new Message(user.toString() + " has left the chat", new User("SERVER", null))));
            } catch (IOException ex) {
                Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
            }

            if (output != null){
                writers.remove(output);
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ex) {
                    Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (os != null){
                try {
                    os.close();
                } catch (IOException ex) {
                    Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (input != null) {
                try {
                    input.close();
                } catch (IOException ex) {
                    Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
}

РЕДАКТИРОВАТЬ: вот трассировка стека

11 ноября 2019 г. 12:44:21 instachatfx.server.ServerMain $ Выполнение обработчика SEVERE: null java.io.EOFException at java.io.ObjectInputStream $ BlockDataInputStream.peekByte (ObjectInputStream.java:2950) в java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1534) в java.io.ObjectInputStream.readObject (ObjectInputStream.java:427) в instachatfx.server.ServerMain $ Handler.run (ServerMain.java:83)

1 Ответ

1 голос
/ 10 ноября 2019

Я не понимаю, почему я получаю эту ошибку ...

Вы получаете ошибку, потому что один конец закрыл свой выходной поток ... или весь сокет,Это может быть результатом явного закрытия или закрытия приложения.

... поскольку ни клиент, ни сервер не отправляют сообщение ...

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

... означает, что нет файла, которого можно достичь до конца.

Ваша логика неверна. "Файл", который упоминается, является потоком, упомянутым выше. Если вы закроете конец записи, конец чтения увидит конец потока / конец файла, если попытается продолжить чтение.


Похоже, псевдоанонимный комментатор обнаружил ошибку, которая, вероятно, объясняеттвоя проблема. Метод Socket.isConnected() нельзя использовать для проверки, подключен ли еще сокет. javadoc состояния:

 public boolean isConnected()

Возвращает состояние соединения сокета.

Примечание. Закрытие сокета не очищает состояние соединения, , что означает, что этот метод будет возвращать true для закрытого сокета (см. isClosed()), если он был успешно подключен до закрытия .

Возвращает: true, если сокет был успешно подключен к серверу

(выделение добавлено ...)


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

...