Как прервать поток, если это открыть сокет? - PullRequest
4 голосов
/ 13 марта 2012

Я попытался закрыть текущий поток, который является частью многопоточного сервера.Поток готов открыть сокет, к которому могут обращаться клиенты.

Все работает нормально, кроме случаев, когда приведенный ниже код содержится в цикле while ().

new ServerThread (serversocket.accept (), this.Rstr, bag.numberofDatatoAcquire) .start ();

Вот код для сервера:

public void run() {

    System.out.println("This has been called ");   

    try{

       System.out.println("This has been tried");    
       serversocket = new ServerSocket(this.iPort);                                 

       Thread thisThread = Thread.currentThread();

       while(!thisThread.isInterrupted()){
           new ServerThread(serversocket.accept(), this.Rstr, bag.numberofDatatoAcquire).start();
           //sending socket accessed, where it will store the data and how much it will collect it.                            
           System.out.println("This has been running");                  
           Thread.sleep(10);               
       }           
    }catch(InterruptedException e){
        //why bother? it is an usual happening...lol
    }catch(IOException ioe)
    {
        System.err.println("Can't open the socket on port");               
    }
    finally{     
       System.out.println("Thread is dead and ready for change");
    }
}

И это часть событий GUI: это работает хорошо без кода «new ServerThread ...».

private OverWatch EW = new OverWatch(bag.iPortOrder, bag.SessionAcquisitionSavingDirectory);   

....

private void OverWatcherControl(boolean checker)
{
    if(checker)
        EW.start();  
    else
        EW.interrupt();

}

Поскольку переменная bag.numberofDataToAcquire (открытый целочисленный тип) должна изменяться всякий раз, когда пользователь хочетЯ думаю, что я должен остановить этот поток и изменить переменную, а затем снова запустить этот поток.Я ошибся?Или как мне прервать эту тему?

Спасибо,

Ответы [ 3 ]

11 голосов
/ 13 марта 2012

ServerSocket.accept() - это блокирующий вызов, который не реагирует на прерывание потока.Почти все блокирующие вызовы java.net (подключение, чтение, принятие и т. Д.) Не отвечают на Thread.interrupt ().Это поведение «как задумано».

Чтобы разбудить поток, заблокированный в .accept() или .read(), нужно закрыть базовый сокет.

В качестве альтернативы вы можете установить SO_TIMEOUT (setSoTimeout) на ServerSocket, что приведет к периодическому пробуждению .accept(), выдав SocketTimeoutException.Вы можете перехватить это исключение и использовать его как возможность проверить состояние прерывания в потоке.

Пакет java.nio (Java 1.4+) предоставляет API альтернативных сокетов, более чувствительный к прерыванию.

6 голосов
/ 13 марта 2012

Так же, как альтернатива использованию таймаута или уничтожение сокета:

Подделка новое подключение к розетке. Это «разбудит» accept(), и тогда можно будет использовать дополнительный механизм сигнализации (например, проверку флага или прерывания) (хотя логика должна быть слегка изменена, чтобы не «лежать» в println).

Я использовал этот подход раньше, и он работал хорошо: не нужно ждать тайм-аута (даже сортировки) или обрабатывать другое исключение, и сокет остается открытым / действительным (что может или не может быть желательным). С другой стороны, я не уверен, что произойдет с действительно длинным / сломанным TCP-рукопожатием, но я никогда не сталкивался с этим; -)

Удачного кодирования.

2 голосов
/ 13 марта 2012

Сначала я ответил на него, используя serverSocket.setSoTimeout(millis) и обработав SocketTimeoutException.См. Ниже.

Лучший способ сделать это - использовать ServerSocketChannel, который прерывается при вызове accept() при вызове thread.interrupt(), поэтому вам вообще не нужно вращаться.Так что вы бы сделали что-то вроде:

ServerSocketChannel socketChannel = ServerSocketChannel.open();
socketChannel.socket().bind(new InetSocketAddress(this.iPort), 10);
...
while (! thisThread.isInterrupted()) {
    // channel accepts _are_ interrupted by the call to thread.interrupt()
    // it throws ClosedByInterruptException when interrupt() is called
    SocketChannel accepted = socketChannel.accept();
    new ServerThread(accepted.socket(), this.Rstr,
        bag.numberofDatatoAcquire).start();
}

Я попробую объяснить код:

while(!thisThread.isInterrupted()){
   new ServerThread(serversocket.accept(), this.Rstr,
        bag.numberofDatatoAcquire).start();
   Thread.sleep(10);               
}           

Я думаю, что ваша проблема здесь в том, что serversocket.accept() висит в ожидании принятия сокета.Из accept() javadocs :

Прослушивает подключение к этому сокету и принимает его.Метод блокируется, пока не будет установлено соединение.

Вам необходимо установить тайм-аут на вашем сокете до цикла while.Для этого вы можете использовать setSoTimeout(millis).

serversocket.setSoTimeout(10000);

Затем будет выброшено SocketTimeoutException, если истечет время ожидания.Тогда вам не понадобится Thread.sleep(10) (что соответствует 10мс между прочим), потому что сон будет выполняться внутри метода accept().Я бы не рекомендовал accept(10), потому что это крутилось бы довольно агрессивно.

...