Java - ClientSocket not closing program

47 Views Asked by At

I am creating simple chat app in Java using ClientSocket and ServerSocket. However I have come to a problem.

The Client has two threads, one for reading received messages and the other for sending messages. When the client writes 'exit' the application should close together with the connection. However the application doesn't close but only after the client has received some messages from other clients which should not happen.

Can anybody help me fix this ?

Client.java

    import java.io.*;
import java.net.Socket;
import java.net.ConnectException;
import java.util.Scanner;

public class Client {

    private Socket clientSocket;
    private BufferedReader serverReader;
    private boolean stopReceiving;
    private boolean stopSending;

    public static void main(String[] args) {
        Client client = new Client();
    }

    public Client() {
        try {
            this.clientSocket = new Socket("localhost", 8080);
            System.out.println("Spuštění klienta proběhlo úspěšně.");

            this.serverReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            this.stopReceiving = false;
            this.stopSending = false;


            Thread receiveThread = new Thread(new Runnable() {
                public void run() {
                    try {
                        while (!stopReceiving) {
                            String message = serverReader.readLine();
                            if (message == null) {
                                // Vypnutí připojení k serveru
                                stopReceiving = true;
                                closeClient();
                                System.exit(0); // Vypnutí aplikace
                            }
                            if (message.equals("Připojení odmítnuto - dosaženo maximálního počtu klientů. Zkuste se připojit později.")) {
                                closeClient();
                                System.exit(0); // Vypnutí aplikace
                            }
                            System.out.println("Zpráva od serveru: " + message);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
            receiveThread.start();

            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(this.clientSocket.getOutputStream())); // vytvoření BufferedWriter
            Scanner in = new Scanner(System.in);
            while (!stopSending) {
                String message = in.nextLine();
                if (message.equals("exit")) {
                    System.out.println("REACHED EXIT");
                        serverReader.close();
                        clientSocket.close();
                        in.close();
                        out.close();
                        System.out.println("EXITED");

                        System.exit(0);
                        break;

                }else{
                    out.write(message + "\r\n");
                    out.flush();
                    System.out.println("Zpráva \"" + message + "\" byla odeslána.");
                }
            }

        } catch (ConnectException e) {
            System.out.println("Nepodařilo se připojit k serveru. Klient se ukončuje.");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeClient();
        }
    }

    private void closeClient() {
        try {
            if (serverReader != null)
                serverReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (clientSocket != null)
                clientSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Server.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;

public class Server {

    private ServerSocket serverSocket;
    private ArrayList<ClientHandler> clients;
    private static final int MAX_CLIENTS = 2; // Maximální počet klientů

    public static void main(String[] args) {
        Server server = new Server();
    }

    public Server() {
        try {
            this.serverSocket = new ServerSocket(8080);
            System.out.println("Spuštění serveru proběhlo úspěšně.\nČekám na připojení klienta...\n");
            this.clients = new ArrayList<>();

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

    private void clients() {
        Thread acceptThread = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        Socket clientSocket = serverSocket.accept();
                        PrintWriter writer = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()), true);
                        if (clients.size() < MAX_CLIENTS) { // Check if the maximum number of clients is reached
                            ClientHandler clientHandler = new ClientHandler(clientSocket, writer);
                            synchronized (clients) {
                                clients.add(clientHandler);
                            }
                            System.out.println("Klient " + clientHandler.getAddress() + " se připojil.");
                        } else {
                            writer.println("\"Připojení odmítnuto - dosaženo maximálního počtu klientů. Zkuste se připojit později.");
                            writer.flush();
                            clientSocket.close();
                            System.out.println("Připojení odmítnuto - dosaženo maximálního počtu klientů.");
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        acceptThread.start();

        while (true) {
            synchronized (clients) {
                Iterator<ClientHandler> iterator = clients.iterator();
                while (iterator.hasNext()) {
                    ClientHandler clientHandler = iterator.next();
                    try {
                        BufferedReader reader = new BufferedReader(new InputStreamReader(clientHandler.getSocket().getInputStream()));
                        if (reader.ready()) {
                            String message = reader.readLine();
                            System.out.println("Přijata zpráva od klienta " + clientHandler.getAddress() + " : " + message);
                            broadcastMessage(message);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        iterator.remove(); // Bezpečně odstraní klienta z iterátoru
                    }
                }
            }
        }
    }

    private void broadcastMessage(String message) {
        synchronized (clients) {
            for (ClientHandler clientHandler : clients) {
                clientHandler.getWriter().println(message);
                clientHandler.getWriter().flush();
            }
        }
    }

    private static class ClientHandler {
        private final Socket socket;
        private final PrintWriter writer;

        public ClientHandler(Socket socket, PrintWriter writer) {
            this.socket = socket;
            this.writer = writer;
        }

        public Socket getSocket() {
            return this.socket;
        }

        public PrintWriter getWriter() {
            return this.writer;
        }

        public String getAddress() {
            return this.socket.getInetAddress().toString();
        }
    }
}
1

There are 1 best solutions below

4
On

The problem is that you are closing serverReader here:

if (message.equals("exit")) {
                System.out.println("REACHED EXIT");
                serverReader.close();
                clientSocket.close();
                in.close();
                out.close();
                System.out.println("EXITED");

                System.exit(0);
                break;

            }

The application doesn't exit, because there is a lock set on serverReader object in receiveThread by the method readLine(). When you call serverReader.close() it waits until lock gets released, and it gets released when the message is received in that case. If you remove that line it will work:

if (message.equals("exit")) {
                System.out.println("REACHED EXIT");
                clientSocket.close();
                in.close();
                out.close();
                System.out.println("EXITED");

                System.exit(0);
                break;

            }