Java 文件结束异常

Java End of File Exception

我正在使用 JavaFX 编写一个简单的即时消息传递程序,遇到了文件结束异常,经过数小时的调试我找不到解决方案。

我的程序分两部分编写,客户端和服务器端。它们相互发送序列化对象,其中包含完成所需操作所需的所有必要信息。当我开始在服务器中收到此错误时,我正在向我的程序添加其他功能。我已经删除了所有附加代码,但仍然收到此错误消息。我不明白为什么我会收到此错误,因为客户端和服务器都没有发送消息,这意味着没有文件可以到达结尾??

我注释掉调用方法 "sendMessage()" 的行,这似乎解决了问题,但我需要此方法才能工作。

下面是服务器的副本class

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);
                }
            }
        }
    }
}

编辑:这里是堆栈跟踪

2019 年 11 月 11 日 12:44:21 下午 instachatfx.server.ServerMain$Handler 运行 严重:无 java.io.EOFException 在 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)

I don't understand why I'm getting this error ...

您收到错误是因为一端已关闭其输出流...或整个套接字。这可能是显式关闭的结果,也可能是因为应用程序已退出。

... as neither the client nor the server are sending a message ...

应用程序(客户端或服务器)正在尝试读取一条消息,但不会收到任何消息,因为另一端已关闭该端正在尝试读取的流来自.

... meaning there's no file to reach the end of.

你的逻辑不正确。所指的"file"就是上面所指的流。如果关闭写入端,如果读取端尝试继续读取,则读取端会看到流结束/文件结束。


伪匿名评论者似乎发现了一个错误,可能可以解释您的问题。 Socket.isConnected() 方法不能用于测试套接字是否仍处于连接状态。 javadoc 状态:

 public boolean isConnected()

Returns the connection state of the socket.

Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket (see isClosed()) if it was successfully connected prior to being closed.

Returns: true if the socket was successfully connected to a server

(重点添加...)


如果您需要更多帮助,请提供适当的 minimal reproducible example,并确保包括异常的完整堆栈跟踪。