Proper way to terminate thread

I'm trying to write chat application based on Sockets but I'm a bit confused, how to actually stop my server.

Here is my Server constructor

    public Server(int port) {
        this.port = port;
        this.shutdown = false;
        this.clientComponentSet = new HashSet<>();
        LOGGER.info("Starting the server...\n");

        dbConnection = new DBConnection();
        dbConnection.establish();
        if(dbConnection.isConnected()) {
           LOGGER.info("Established connection with database\n");
        } else {
           LOGGER.warn("Can't establish connection with database\n");
        }

        machineString = new SimpleStringProperty();
        addressString = new SimpleStringProperty();
        portString = new SimpleStringProperty();
        status = new SimpleStringProperty();
        status.set("Offline");
    }

Then goes run method

@Override
    public void run() {
        try {
            serverSocket = new ServerSocket(port);

            Platform.runLater(
                    () -> {
                        try {
                            machineString.set(serverSocket.getInetAddress().getLocalHost().getHostName());
                            addressString.set(serverSocket.getInetAddress().getLocalHost().getHostAddress());
                        } catch (UnknownHostException e) {
                            LOGGER.error(e.toString());
                        }
                        portString.set(String.valueOf(this.port));
                        status.set("Online");
                    }
            );

            LOGGER.info("Server started\n");

            while(!serverSocket.isClosed() && !shutdown) {
                Socket clientSocket = serverSocket.accept();
                ClientComponent clientComponent = new ClientComponent(this, clientSocket);
                clientComponentSet.add(clientComponent);
                clientComponent.start();
            }
        } catch (IOException e) {
            LOGGER.error("Failed to start the server\n" + e.toString() + "\n");
        }
    }

and finnaly, method that should stop/close server

public void stopServer() {
        try {
            serverSocket.close();
            shutdown = true;
            LOGGER.info("Server stopped\n");
        } catch (IOException e) {
            LOGGER.error(e.toString());
        }
    }

Although, it isnt working as I expected. I start and then stop my server and logs are like this:

2018-03-17 12:48:01 INFO Starting the server...

2018-03-17 12:48:02 INFO Established connection with database

2018-03-17 12:48:03 INFO Server started

2018-03-17 12:48:04 INFO Server stopped

2018-03-17 12:48:04 ERROR Failed to start the server java.net.SocketException: socket closed

Trying to start server again now, will throw

Exception in thread "JavaFX Application Thread" java.lang.IllegalThreadStateException

How exactly can I stop/close my server then?

I actually forgot about my ServerController class

public class ServerController {
    final static Logger LOGGER = Logger.getLogger(ServerController.class);
    private ServerController(){
    }
    private static ServerController instance = null;

    public static ServerController getInstance() {
        if(instance == null) {
            instance = new ServerController();
        }
        return instance;
    }

    private Server server;

    public void start() {
        server = new Server(Integer.parseInt(Property.getByKey("SERVER_PORT")));
        server.start();
        if(!server.isAlive()) {
            LOGGER.info("Server closed\n");
        }
    }
}

2 answers

  • answered 2018-03-17 11:56 Peter Lawrey

    At least one confusing thing you can fix is that your ERROR will even if closeServer() is called.

    I suggest;

    • you make shutdown volatile
    • you always set it first
    • you check whether the server was shutdown, and only print the error if it wasn't.
    • don't assume the exception means it didn't start.
    • always print the Exception with a stack trace to get the cause unless you are very confident it's not needed.

    To restart a thread, you need to create a new one, to listen to a port after it has been closed, you need to create a new ServerSocket.

    BTW You don't need to add extra new lines at the end of logs.

  • answered 2018-03-17 11:56 Dusty

    You are receiving the "Server failed to start" message you close the ServerSocket while it is waiting for a connection to be established. The ServerSocket.accept method will block your thread until it receives some input. I believe the best way to solve this is to send it some "shutdown" signal when you wish to terminate the server. When the shutdown signal/message is received you can then safely close the ServerSocket and terminate your while loop.