How to break an infinite loop using Ctrl-C in Java

Asked

Viewed 218 times

1

I have a multithreaded server that sits in an infinite loop waiting for new connections and I want to be able to stop this loop when I press Ctrl-C (or something similar). I tried to use that one solution and tried to do something like this:

private void waitForConnections() {
    boolean done = false;
    Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
            super.run();
            System.err.println("Exiting");
            done = true;
        }
    });

    while (!done) {
        try {
            Socket userSocket = this.serverSocket.accept();
            // Faz alguma coisa...
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

But I cannot change the value of the done variable within the thread. How can I solve this problem in the simplest and most elegant way possible?

  • 2

    There is an error because your code will never test the !done, because you have a while(true).

  • The problem has been solved?

  • 1

    The question is very interesting, I wanted to answer but I do not know if I will find time. By the way, I believe that super.run() is not necessary.

  • Sveen, Not yet. The error that the lemoce said to fix was a code typing error. The main problem persists!

  • Try to set setSoTimeout(), then the Accept will release a SocketTimeoutException, so that the Accept is not blocked endlessly. If this is the solution, it is because Accept keeps blocking the thread endlessly, just when you emit Ctrl-C, your code does not go back to the beginning of the loop and so test the !done.

  • It does not seem a good solution because the server will be on for hours and it may happen that no client wants to connect. In your solution the server would stop receiving requests after the timeout occurs.

  • @Michaelpacheco may be. I gave a solution, but the important thing is why the problem happens.

Show 2 more comments

2 answers

0

I got a temporary solution while others do not appear. What I did was just replace the ShutdownHook by a Thread normal and within the method run I made an infinite loop that reads the user input and stops when it enters end of file (Ctrl+D on MAC). But I’m still not satisfied with this solution... it seems to me.

Here is my code:

private void waitForConnections() {
    new Thread(this).start();

    try {
        //noinspection InfiniteLoopStatement
        while (true) {
            Socket userSocket = this.serverSocket.accept();
            allocateClient(userSocket);
        }
    } catch (IOException e) {
        // The user socket was closed by the shutdown method, so, no need for printing the stack trace.
        //e.printStackTrace();
    }
}

@Override
public void run() {
    Scanner s = new Scanner(System.in);
    while (s.hasNext())
        s.nextLine();

    shutdown();
}

The shutdown method closes the ServerSocket generating a IOException inside the loop.

-1

I made a example minimum and functional Stackoverflow site. In my example, I didn’t need to add a finishing hook. The operation is very simple, a Thread was created to be the application’s Listener and another Handler to treat customers. I don’t know if it’s the ideal solution to your problem and I’m sure you have problems.

import java.io.PrintWriter;

import java.net.Socket;
import java.net.ServerSocket;

import java.util.concurrent.TimeUnit;

public class Teste {

    static class Listener extends Thread {

        public void run() {
            try (ServerSocket ss = new ServerSocket(10113)){
                System.out.println("Iniciei servidor");
                while(true) {
                    try {
                        System.out.println("Esperando cliente");
                        Handler handler = new Handler(ss.accept());
                        handler.start();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                System.exit(-1);
            }

        }

    };

    static class Handler extends Thread {

        Socket client;

        public Handler(Socket client) {
            this.client = client;
        }

        public void run() {
            try (PrintWriter writer = new PrintWriter(client.getOutputStream(), true)) {
                writer.println("meu super teste");
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                if (client != null) {
                    try {
                        client.close();
                    } catch (Exception ex) {
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Teste.Listener listener = new Teste.Listener();
        listener.setDaemon(true);
        listener.start();
        try {
            System.out.println("esperando servidor iniciar");
            TimeUnit.SECONDS.sleep(30);
        } catch (Exception ex) {}
    }

}
  • This code shows nothing related to my problem. I need a simple and elegant way to stop the server when I want and disconnect all users. But thanks for trying to help!

  • Why did you deny me?

  • @Michaelpacheco I just wanted to show that one can do Ctrl-C without explicit Hooks or shutdown.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.