Остановка потока цикла ServerSocket accept()

#java #multithreading #sockets #tcp #serversocket

#java #многопоточность #сокеты #tcp #serversocket

Вопрос:

Я внедряю очень простой API, чтобы иметь лучший контроль над ServerSocket и сокетами, но у меня очень странная проблема, которую я не могу решить из-за недостатка знаний о потоках. Позвольте мне объяснить это.

В моем классе SocketStreamReceiver я использую вторичный поток для прослушивания новых сокетов с помощью ServerSocket#accept() . Существует 2 метода: start() и stop(), которые клиент может использовать для запуска (создания потока и начала прослушивания с accept() ) и остановки (закрытия ServerSocket и уничтожения потока) моего SocketStreamReceiver.

Как вы будете реализовывать метод stop()?Имейте в виду, что stop() может быть вызван внутри doSomething() в том же вторичном потоке, запущенном start(). Вы можете изменить все, что хотите: вы можете создать ServerSocket внутри потока, если хотите, непосредственно перед while (запуск).

 public class SocketStreamReceiver{
    ...
    private Thread thread;
    private ServerSocket server;
    private boolean running;
    ...

    public void start () throws IOException{
        if (thread != null) return;

        server = new ServerSocket (port);
        thread = new Thread (new Runnable (){
            @Override
            public void run (){
                try{
                    while (running){
                        Socket socket = server.accept ();
                        doSomething (socket);
                    }
                }catch (SocketException e){
                    ...
                }catch (IOException e){
                    ...
                }
            }
        }, "SocketStreamReceiver");
        thread.start ();
    }

    public void stop () throws IOException{
        if (thread == null) return;

        //code...

        thread = null;
    }
}
  

Спасибо.

РЕДАКТИРОВАТЬ — Решение:

 public class SocketStreamReceiver{
    private Thread thread;
    private ServerSocket server;
    private volatile boolean running;
    ...

    public synchronized void start () throws IOException{
        if (thread != null) throw new IllegalStateException ("The receiver is already started.");

        server = new ServerSocket (port);
        thread = new Thread (new Runnable (){
            @Override
            public void run (){
                try{
                    running = true;
                    while (running){
                        doSomething (server.accept ());
                        ...
                    }
                }catch (SocketException e){
                    ...
                }catch (IOException e){
                    ...
                }
            }
        }, "SocketStreamReceiver");
        thread.start ();
    }

    public synchronized void stop (){
        if (thread == null) return;

        running = false;
        try{
            if (server != null){
                server.close ();
            }
        }catch (IOException e){}

        thread = null;
    }
}
  

Ответ №1:

Я бы просто сделал

 public void stop() {
    running = false;
    try{
        if (server != null) server.close ();
    } catch (IOException ignored){
    }
}
  

Похоже, вам даже не нужен флаг running. Однако я бы использовал это в коде принятия вашего сервера, чтобы определить, ожидается исключение или нет. т. Е. при запуске == false игнорируйте все исключения.

Я бы сделал running volatile.

Я бы синхронизировал start () / stop (), если вы можете запускать их из разных потоков.

Комментарии:

1. Если вызывается server.close() и после того, как мы выполним server.accept(), что произойдет? Блокирует ли ServerSocket поток?

2. Accept() вызовет исключение SocketException, которое вам все равно придется перехватить.

3. Почему вы перехватываете исключение И генерируете его?

4. @MByD, потому что я забыл его удалить. Спасибо.