Как разблокировать поток, заблокированный на ServerSocket.accept ()? - PullRequest
6 голосов
/ 02 октября 2009

У меня есть нить на сервере с этим кодом:

public void run() {
    try {
        ServerSocket server;
        EneaLog.printLog("Server is running.");
        server = new ServerSocket(this.portnumber);

        while (true) {
            new EneaServerConnection(server.accept(), this.project,stopped).start();
            if (stopped) {
                EneaLog.printLog("Server safe-shutdown completed.");
                EneaLog.printLog("Hi!");
                server.close();
                return;
            }
        }
    } catch (IOException ex) {
        Logger.getLogger(EneaServer.class.getName()).log(Level.SEVERE, null, ex);
        project.getExceptionHandler().handler(ex);
    }
}

и способ выключения, подобный этому:

public void shutdown() {
    EneaLog.printLog("Server shutdown NOW!");
    stopped = true;
}

Я хочу, чтобы при завершении работы можно было разблокировать поток, ожидающий на сервере server.accept (), в противном случае я должен дождаться соединения перед отключением сервера.

Я не могу выполнить server.close () в shutdown (), потому что я должен сообщить зарегистрированному клиенту, что сервер отключается.

Есть идеи?

Ответы [ 5 ]

4 голосов
/ 02 октября 2009

Я пытаюсь спроектировать свой код так, чтобы он мог быть "отключен" с прерыванием. Главным образом, это связано с тем, что Executor инфраструктура в пакете параллелизма Java использует interrupt для отмены запущенных задач. Кроме того, задача «завершение работы» не должна знать какие-либо внутренние элементы этой задачи.

Однако вызов accept не будет отвечать на прерывание , если это , созданное из ServerSocketChannel. Сервер, созданный с помощью конструктора ServerSocket, будет игнорировать прерывания, и я не нашел способ перенастроить это.

Если вы не можете изменить код, который создает сервер, организуйте другой поток для вызова close на сокете сервера. Это также вызовет исключение в потоке, заблокированном на accept, независимо от метода, использованного для создания сокета сервера.

Оказывается, это очень большая боль при использовании SSL. Сокет JSSE не создается из InterruptibleChannel и не будет реагировать на простое прерывание в потоке.


Я только что заметил, что в вопросе говорится, что сервер не может быть закрыт без уведомления клиента. Успешное прерывание сокета приводит к его закрытию.

При вызове accept это не должно быть проблемой, так как клиент не подключен, если сокет сервера заблокирован при принятии. Это должно быть проблемой только для Socket экземпляров, которые представляют текущие соединения.

Если это не удовлетворяет требованиям уведомления, может потребоваться доработка для использования NIO ServerSocketChannel в неблокирующем режиме.

2 голосов
/ 27 ноября 2010

Ни прерывание (это зависит от точек прерывания точно так же, как отмена зависит от точек отмены), ни close не будут это делать (accept не отвечает на закрытие дескриптора файла). Вам нужно будет связаться с accept (попробуйте sendto, с уведомлением о завершении работы), чтобы уведомить его, чтобы он не продолжал принимать. По крайней мере, так обстоит дело в Linux; не знаю, как на других платформах.

2 голосов
/ 02 октября 2009

Вы должны иметь возможность закрыть сокет из другого потока.

1 голос
/ 19 декабря 2011

Я столкнулся с той же проблемой. Мои рабочие решения заключаются в закрытии объекта ServerSocket (serverSocket.close ()); это приведет к тому, что метод accept () сгенерирует исключение SocketException, что вы и хотите сделать.

Винсент

0 голосов
/ 02 октября 2009

Вы пробовали Thread.interrupt () ?

Если этот поток заблокирован в I / O операция на прерываемой канал, то канал будет закрыто, статус прерывания потока будет установлен, и поток будет получить исключение ClosedByInterruptException.

Если эта тема заблокирована в Селектор, а затем прерывание потока статус будет установлен, и он вернется сразу из выбора операция, возможно, с ненулевым значение, как будто селектор метод пробуждения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...