Terchila Marian
Terchila Marian

Reputation: 2520

Java socket write error when client disconnects from server

I am working on a chat app in Java and so far everything works all right except that when a client disconnects and a message is send by other client this error pops out:

  java.net.SocketException: Software caused connection abort: socket write error
    at java.base/java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.base/java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:110)
    at java.base/java.net.SocketOutputStream.write(SocketOutputStream.java:150)
    at java.base/java.io.DataOutputStream.write(DataOutputStream.java:107)
    at java.base/java.io.DataOutputStream.writeUTF(DataOutputStream.java:401)
    at java.base/java.io.DataOutputStream.writeUTF(DataOutputStream.java:323)
    at com.terkea/com.terkea.system.server.ClientThread.run(ClientThread.java:65)
    at java.base/java.lang.Thread.run(Thread.java:835)

This is my server Thread:

@Override
public void run() {
    try {
        DataInputStream in = new DataInputStream(socket.getInputStream());
        DataOutputStream out = new DataOutputStream(socket.getOutputStream());

        while (!socket.isClosed()) {
            try {
                    String input = in.readUTF();
                    if (Message.fromJSON(input).getUserName().equals("REGISTER")) {
                        Message specialMessage = Message.fromJSON(input);
                        specialMessage.setUserName("SERVER");

                        Client test = Client.fromJSON(specialMessage.getMessage());
                        test.setIp(socket.getInetAddress().toString());
                        test.setListening_port(String.valueOf(socket.getPort()));
                        specialMessage.setMessage(Client.toJSON(test));

                        input = Message.toJSON(specialMessage);

                    }
                    for (ClientThread thatClient : server.getClients()) {
                        DataOutputStream outputParticularClient = new DataOutputStream(thatClient.getSocket().getOutputStream());
                        outputParticularClient.writeUTF(input);
                    }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    } catch (IOException e) {
        e.printStackTrace();
    }
}

and the Client:

public void createClient() {

    try {
        socket = new Socket(getHost(), portNumber);

        DataInputStream in = new DataInputStream(socket.getInputStream());
        out = new DataOutputStream(socket.getOutputStream());
        Message registerclient = new Message("REGISTER", Client.toJSON(getClient()));
        out.writeUTF(Message.toJSON(registerclient));

        new Thread(() -> {
            while (!socket.isClosed()) {
                try {
                    if (in.available() > 0) {
                        String input = in.readUTF();
                        Message inputMessage = Message.fromJSON(input);
                        if (inputMessage.getUserName().equals("SERVER")) {
                            System.err.println(Client.fromJSON(inputMessage.getMessage()));
                            allClientsConnected.add(Client.fromJSON(inputMessage.getMessage()));
                        } else {
                            chat.add(inputMessage);
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

The error corresponds to outputParticularClient.writeUTF(input);

My goal is to get rid of this error and also if possible could anybody tell me a way to check when a client disconnects? I've found some similar questions over here and their solution was to check if (socket.getInputStream().read()!=-1) but when I do that the whole program freezes and the GUI stops working.

Upvotes: 0

Views: 706

Answers (1)

kendavidson
kendavidson

Reputation: 1460

You may want to look into expanding upon your special message functionality, and instead of using the username to pass "REGISTER" use something like messageType in order to do so. This way you can configure handlers based on type to do a number of things. For example things like:

MessageType { REGISTER, UNREGISTER, READ_RECEIPT, ... }

You can then have things like:

RegisterHandler {}
UnregisterHandler{}

and eventually expand them to have some features like facebook/whatsapp (/ICQ haha):

TypingHandler {} // Other user gets a message saying that I am typing to them

From here, you can implement the UNREGISTER to do what you want. Like the first comment says, you should catch the SocketException and manually unregister that client so it doesn't happen anymore. But you should also try to pre-emptively send an

{
    messageType: UNREGISTER,
    from: Client1
    to: server|null,
    data: {}
 }

so that your server can remove it before the exception occurs. This would also let you handle Offline messages, if that's something you're interested in.

Upvotes: 1

Related Questions