1

I'm writing an email application in javafx, using MVC architecture. The starting method of the server is this.

    @Override
    public void run() {
        try {
            serverSocket = new ServerSocket(PORT);
            controller.logEvent(Protocol.SERVER_STARTED, true, null, null);
            loadAccounts();
            while (isRunning.get()) {
                try {
                    Socket socket = serverSocket.accept();
                    if (isRunning.get()) {
                        connectedClients.add(socket);
                        Thread thread = new Thread(() -> {
                            handleClient(socket);
                            connectedClients.remove(socket);
                        });
                        thread.start();
                    } else {
                        socket.close();
                    }
                } catch (SocketException e) {
                    if (!isRunning.get()) {
                        break;
                    } else {
                        throw e;
                    }
                }
            }
        } catch (IOException e) {
            controller.logEvent(Protocol.SERVER_STARTED, false, null, null);
            e.printStackTrace();
        }
    }

While instead the one to stop the server is this:

    public void stopServer() {
        isRunning.set(false);
        try {
            if (serverSocket != null) {
                serverSocket.setReuseAddress(true);
                serverSocket.close();
                controller.logEvent(Protocol.SERVER_STOPPED, true, null, null);
                for (Socket socket : connectedClients) {
                    socket.close();
                }
                connectedClients.clear();
            }
        } catch (IOException e) {
            controller.logEvent(Protocol.SERVER_STOPPED, false, null, null);
            e.printStackTrace();
        }
    }

My problem lies in restarting the server. When I try to restart it, it gives me these errors:

java.net.BindException: Address already in use (Bind failed)
    at java.base/java.net.PlainSocketImpl.socketBind(Native Method)
    at java.base/java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:452)
    at java.base/java.net.ServerSocket.bind(ServerSocket.java:395)
    at java.base/java.net.ServerSocket.<init>(ServerSocket.java:257)
    at java.base/java.net.ServerSocket.<init>(ServerSocket.java:149)
    at MailServer.run(MailServer.java:71)
    at java.base/java.lang.Thread.run(Thread.java:829)

My method for restarting the server was this:

    public void startServer() {
        try {
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.setReuseAddress(true);
                serverSocket.close();
            }
            isRunning.set(true);
            serverSocket = new ServerSocket(PORT);
            Thread thread = new Thread(this);
            thread.start();
            controller.logEvent(Protocol.SERVER_STARTED, true, null, null);
        } catch (IOException e) {
            controller.logEvent(Protocol.SERVER_STARTED, false, null, null);
        }
    }

Do you have any tips to solve my problem? I figured out that the problem is that the port is not freed when the server is stopped, but I have no idea how I can fix it.

2
  • I think the main problem is that run() creates a new ServerSocket on the same port as the one created by the startServer() method. Given the presence of a startServer() method, you should remove the creation of the ServerSocket in the run() method. Additionally, you seem to be using #setReuseAddress(boolean) incorrectly. The effects of that method are undefined for an already-bound socket. Create an unbound socket, call that method, then call bind. Commented Mar 11, 2023 at 3:43
  • where is the relation to fx? Commented Mar 14, 2023 at 0:25

1 Answer 1

0

REUSEADDR is not about 'freeing' an address on close, it is about permitting binding to an address that is in use. The address (port) will be 'in use' for some after the socket is closed, that's just how the protocol has to work.

When you initially bind the socket in your 'run' method, you create it without REUSEADDR, and that is where your exception comes from.

I'm not that familiar with the Java server socket (but have experience with sockets in C), but the documentation says that what you want to do is

Create an unbound socket (with the no-arguments constructor)
Set REUSEADDR
Bind the socket to an interface and port

in that order. Don't bother with the close-time stuff, but do this every time you create a new ServerSocket.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.