Ошибка записи сокета Java при отключении клиента от сервера - PullRequest
0 голосов
/ 10 июня 2019

Я работаю над приложением чата на Java, и пока все работает нормально, за исключением того, что, когда клиент отключается и сообщение отправляется другим клиентом, появляется эта ошибка:

  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)

Это моеПоток сервера:

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

и клиент:

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

Ошибка соответствует outputParticularClient.writeUTF(input);

Моя цель - избавиться от этой ошибки, а также, еслиВозможно ли кто-нибудь сказать мне способ проверить, когда клиент отключается?Я нашел здесь несколько похожих вопросов, и их решением было проверить if (socket.getInputStream().read()!=-1), но когда я это сделал, вся программа зависла, и графический интерфейс перестал работать.

1 Ответ

1 голос
/ 10 июня 2019

Возможно, вы захотите расширить свои специальные функции сообщения, и вместо того, чтобы использовать имя пользователя для передачи «РЕГИСТРАЦИЯ», используйте что-то вроде messageType, чтобы сделать это. Таким образом, вы можете настроить обработчики на основе типа для выполнения ряда задач. Например, такие вещи, как:

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

Вы можете иметь такие вещи, как:

RegisterHandler {}
UnregisterHandler{}

и в конечном итоге расширять их, чтобы иметь некоторые функции, такие как Facebook / WhatsApp (/ ICQ хаха):

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

С этого момента вы можете реализовать UNREGISTER, чтобы делать то, что вы хотите. Как говорится в первом комментарии, вы должны перехватить SocketException и вручную отменить регистрацию этого клиента, чтобы этого больше не происходило. Но вы также должны попытаться превентивно отправить

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...