0

I am writing a simple instant messaging program using JavaFX and have encountered an an End Of File exception and after hours of debugging I cannot find a solution.

My program is written in two parts, the client and the server. They send serialized objects to each other containing all the necessary information to complete the required action. I was adding additional features to my program when I started getting this error in the server. I have since removed all of the additional code but am still getting this error message. 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??

I comment out the line where I call the method "sendMessage()" and that seems to solve the issue but I need this method to work.

Bellow is a copy of the server 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);
                }
            }
        }
    }
}

EDIT: here is the stacktrace

Nov 11, 2019 12:44:21 PM instachatfx.server.ServerMain$Handler run SEVERE: null java.io.EOFException at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2950) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1534) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427) at instachatfx.server.ServerMain$Handler.run(ServerMain.java:83)

4

1 回答 1

1

我不明白为什么我会收到这个错误......

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

...因为客户端和服务器都没有发送消息...

应用程序(客户端或服务器)正在尝试读取消息,但由于另一端已关闭该端尝试从中读取的流,因此不会有消息发出。

...意味着没有文件可以到达末尾。

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


看起来一个伪匿名评论者发现了一个可能解释您的问题的错误。该Socket.isConnected()方法不能用于测试套接字是否仍然连接。javadoc指出:

 public boolean isConnected()

返回套接字的连接状态。

注意:关闭套接字不会清除其连接状态,这意味着如果在关闭之前成功连接,则此方法将为已关闭的套接字返回 true(请参阅 参考资料isClosed()) 。

返回: true如果套接字成功连接到服务器

(强调添加...)


如果您需要更多帮助,请提供适当的最小可重现示例,并确保包含异常的完整堆栈跟踪。

于 2019-11-10T03:27:16.627 回答