java - 服务器端 EOFException

标签 java android server chat

我正在尝试编写一个消息传递应用程序,并且我能够发送消息(显示为服务器客户端正确显示消息)但随后将我的客户端踢出服务器。服务器打印以下错误:

java.io.EOFException at java.io.ObjectInputStream$BlockDataInputStream.peekByte(UnknownSource) at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.readObject(Unknown Source) at com.liftedstarfish.lifte.gpschat0_2.Server$ClientThread.run(Server.java:243)

我的服务器类:

public class Server {
    // a unique ID for each connection
    private static int uniqueId;
    // an ArrayList to keep the list of the Client
    private ArrayList<ClientThread> al;
    // if I am in a GUI
    private ServerGUI sg;
    // to display time
    private SimpleDateFormat sdf;
    // the port number to listen for connection
    private int port;
    // the boolean that will be turned of to stop the server
    private boolean keepGoing;

    private String name;

    /*
     *  server constructor that receive the port to listen to for connection as parameter
     *  in console
     */
    public Server(int port, String name) {
        this(port, name, null);
    }

    public Server(int port, String name, ServerGUI sg) {
        // GUI or not
        this.sg = sg;
        // the port
        this.port = port;

        this.name = name;
        // to display hh:mm:ss
        sdf = new SimpleDateFormat("HH:mm:ss");
        // ArrayList for the Client list
        al = new ArrayList<ClientThread>();
    }

    public void start() {
        keepGoing = true;
        /* create socket server and wait for connection requests */
        try 
        {
            // the socket used by the server
            ServerSocket serverSocket = new ServerSocket(port);

            // infinite loop to wait for connections
            while(keepGoing) 
            {
                // format message saying we are waiting
                display("Server waiting for Clients on " + name + ".");

                Socket socket = serverSocket.accept();      // accept connection
                // if I was asked to stop
                if(!keepGoing)
                    break;
                ClientThread t = new ClientThread(socket);  // make a thread of it
                al.add(t);                                  // save it in the ArrayList
                t.start();
            }
            // I was asked to stop
            try {
                serverSocket.close();
                for(int i = 0; i < al.size(); ++i) {
                    ClientThread tc = al.get(i);
                    try {
                    tc.sInput.close();
                    tc.sOutput.close();
                    tc.socket.close();
                    }
                    catch(IOException ioE) {
                        // not much I can do
                    }
                }
            }
            catch(Exception e) {
                display("Exception closing the server and clients: " + e);
            }
        }
        // something went bad
        catch (IOException e) {
            String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + "\n";
            display(msg);
        }
    }       
    /*
     * For the GUI to stop the server
     */
    protected void stop() {
        keepGoing = false;
        // connect to myself as Client to exit statement 
        // Socket socket = serverSocket.accept();
        try {
            new Socket("localhost", port);
        }
        catch(Exception e) {
            // nothing I can really do
        }
    }
    /*
     * Display an event (not a message) to the console or the GUI
     */
    private void display(String msg) {
        String time = sdf.format(new Date()) + " " + msg;
        if(sg == null)
            System.out.println(time);
        else
            sg.appendEvent(time + "\n");
    }
    /*
     *  to broadcast a message to all Clients
     */
    private synchronized void broadcast(String message) {
        // add HH:mm:ss and \n to the message
        String time = sdf.format(new Date());
        String messageLf = time + " " + message + "\n";
        // display message on console or GUI
        if(sg == null)
            System.out.print(messageLf);
        else
            sg.appendRoom(messageLf);     // append in the room window

        // we loop in reverse order in case we would have to remove a Client
        // because it has disconnected
        for(int i = al.size(); --i >= 0;) {
            ClientThread ct = al.get(i);
            // try to write to the Client if it fails remove it from the list
            if(!ct.writeMsg(messageLf)) {
                al.remove(i);
                display("Disconnected Client " + ct.username + " removed from list.");
            }
        }
    }

    // for a client who logoff using the LOGOUT message
    synchronized void remove(int id) {
        // scan the array list until we found the Id
        for(int i = 0; i < al.size(); ++i) {
            ClientThread ct = al.get(i);
            // found it
            if(ct.id == id) {
                al.remove(i);
                return;
            }
        }
    }

    /*
     *  To run as a console application just open a console window and: 
     * > java Server
     * > java Server portNumber
     * If the port number is not specified 1500 is used
     */ 
    public static void main(String[] args) {
        // start server on port 1500 unless a PortNumber is specified 
        int portNumber = 1500;
        String serverName = "";
        switch(args.length) {
            case 1:
                try {
                    portNumber = Integer.parseInt(args[0]);
                }
                catch(Exception e) {
                    System.out.println("Invalid port number.");
                    System.out.println("Usage is: > java Server [portNumber]");
                    return;
                }
            case 0:
                break;
            default:
                System.out.println("Usage is: > java Server [portNumber]");
                return;

        }
        // create a server object and start it
        Server server = new Server(portNumber, serverName);
        server.start();
    }

    public String getName()
    {
        return this.name;
    }

    /** One instance of this thread will run for each client */
    class ClientThread extends Thread {
        // the socket where to listen/talk
        Socket socket;
        ObjectInputStream sInput;
        ObjectOutputStream sOutput;
        // my unique id (easier for deconnection)
        int id;
        // the Username of the Client
        String username;
        // the only type of message a will receive
        ChatMessage cm;
        // the date I connect
        String date;

        // Constructore
        public ClientThread(Socket socket) {
            // a unique id
            id = ++uniqueId;
            this.socket = socket;
            /* Creating both Data Stream */
            System.out.println("Thread trying to create Object Input/Output Streams");
            try
            {
                // create output first
                sOutput = new ObjectOutputStream(socket.getOutputStream());
                sInput  = new ObjectInputStream(socket.getInputStream());
                // read the username
                username = (String) sInput.readObject();
                display(username + " just connected.");
            }
            catch (IOException e) {
                display("Exception creating new Input/output Streams: " + e);
                return;
            }
            // have to catch ClassNotFoundException
            // but I read a String, I am sure it will work
            catch (ClassNotFoundException e) {
            }
            date = new Date().toString() + "\n";
        }

        // what will run forever
        public void run() {
            // to loop until LOGOUT
            boolean keepGoing = true;
            while(keepGoing) {
                // read a String (which is an object)
                try {
                    //Location of Error
>>>>>>>>>>>>>>>>>>>>cm = (ChatMessage) sInput.readObject();<<<<<<<<<<<<<<<<<
                }
                catch (IOException e) {
                    e.printStackTrace();
                    break;              
                }
                catch(ClassNotFoundException e2) {
                    e2.printStackTrace();
                    break;
                }
                // the messaage part of the ChatMessage
                String message = cm.getMessage();

                // Switch on the type of message receive
                switch(cm.getType()) {

                case ChatMessage.MESSAGE:
                    broadcast(username + ": " + message);
                    break;
                case ChatMessage.LOGOUT:
                    display(username + " disconnected with a LOGOUT message.");
                    keepGoing = false;
                    break;
                case ChatMessage.WHOISIN:
                    writeMsg("List of the users connected at " + sdf.format(new Date()) + "\n");
                    // scan al the users connected
                    for(int i = 0; i < al.size(); ++i) {
                        ClientThread ct = al.get(i);
                        writeMsg((i+1) + ") " + ct.username + " since " + ct.date);
                    }
                    break;
                case ChatMessage.ERROR:
                    broadcast(username + "> " + message);
                    break;
                }
            }
            // remove myself from the arrayList containing the list of the
            // connected Clients
            remove(id);
            close();
        }

        // try to close everything
        private void close() {
            // try to close the connection
            try {
                if(sOutput != null) sOutput.close();
            }
            catch(Exception e) {}
            try {
                if(sInput != null) sInput.close();
            }
            catch(Exception e) {};
            try {
                if(socket != null) socket.close();
            }
            catch (Exception e) {}
        }

        /*
         * Write a String to the Client output stream
         */
        private boolean writeMsg(String msg) {
            // if Client is still connected send the message to it
            if(!socket.isConnected()) {
                close();
                return false;
            }
            // write the message to the stream
            try {
                sOutput.writeObject(msg);
            }
            // if an error occurs, do not abort just inform the user
            catch(IOException e) {
                display("Error sending message to " + username);
                display(e.toString());
            }
            return true;
        }
    }
}

聊天消息类:

public class ChatMessage extends AppCompatActivity implements Serializable {

    protected static final long serialVersionUID = 1112122200L;

    // The different types of message sent by the Client
    // WHOISIN to receive the list of the users connected
    // MESSAGE an ordinary message
    // LOGOUT to disconnect from the Server
    static final int WHOISIN = 0, MESSAGE = 1, LOGOUT = 2, ERROR = 3;
    private int type;
    private String message;

    // constructor
    public ChatMessage(int type, String message) {
        this.type = type;
        this.message = message;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.chat_message);

        final TextView lblMessage = (TextView) findViewById(R.id.text_view_message);

        if(type == MESSAGE)
            lblMessage.setText(message);
    }

    // getters
    public int getType() {
        return type;
    }
    public String getMessage() {
        return message;
    }
}

最佳答案

来自 readObject 文档:

ClassNotFoundException - Class of a serialized object cannot be found.

InvalidClassException - Something is wrong with a class used by serialization.

StreamCorruptedException - Control information in the stream is inconsistent.

OptionalDataException - Primitive data was found in the stream instead of objects.

IOException - Any of the usual Input/Output related exceptions.

EOFException是IOException的一种,当到达文件末尾时抛出。尽管这不会抛出该特定错误,但它确实会抛出 IOException,这意味着它也可以抛出 EOFException。

因此在您的代码中,您只需添加:

while(sInput.available() > 0){// > 0 means there are bytes to read.
    //Read
}

这(理论上)避免了 EOFException。参见 this供引用

关于java - 服务器端 EOFException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43429603/

相关文章:

ios - Swift-NIO 安全的 websocket 服务器

audio - 连续音频下载流

java - Spring Boot 2 - Autowiring 服务时对 Feign 客户端的依赖性不满足

android - 如何以编程方式设置 textView 的样式?

android - 如何以编程方式将按钮逐行添加到布局中?

c# - Xamarin 波斯语日期选择器

java - 由对等方或套接字重置的连接无中生有地关闭

java - Spring-Boot JPA - 使用 JSON RequestBody 中的外键插入数据库会导致空对象

java - 我怎样才能使这个查询只使用 JPA(或 Hibernate)API 工作?

java - 在 java 特殊用例的迭代过程中添加项目