Правильный способ закрыть ServerSocket

Я изучаю использование ServerSocket и получаю сообщение об ошибке при попытке закрыть объект serverSocket, пока работает метод accept(). Затем я нашел решение с помощью метода setSoTimeout(). Но я думаю, что игнорировать исключение - не лучшая практика. Итак, вот мои два класса:

класс Сервер:

public class Server {
    public static final int PORT = 8777;
    private ServerSocket serverSocket;
    private boolean serverRuns;

    Server() {
        try {
            serverSocket = new ServerSocket(PORT);
            serverRuns = true;

            (new Control(this)).start(); // Takes commands while working
            while (serverRuns) {
                try {
                    serverSocket.setSoTimeout(1000);
                    Socket clientSocket = serverSocket.accept();
                }
                catch (SocketTimeoutException e) {
                    // cap
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            try {
                serverSocket.close();
                System.out.println("Server stopped");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public void stopServer() {
        serverRuns = false;
    }
    public boolean isServerRuns() {
        return serverRuns;
    }
    public static void main(String[] Args) {
        Server s = new Server();
    }
}

класс Контроль:

public class Control extends Thread {
    private Server activeServer;

    private Control() {}
    Control(Server activeServer) {
        this.activeServer = activeServer;
    }
    @Override
    public void run() {
        Scanner keyboard = new Scanner(System.in);

        while (activeServer.isServerRuns()) {
            String key = keyboard.nextLine().toLowerCase();

            switch (key) {
                case "close":
                    activeServer.stopServer();
                    break;
            }
        }
    }
}

Это правильный способ завершить работу ServerSocket (игнорировать исключение и проверять переменную serverRuns раз в секунду)? Любые рекомендации приветствуются


person Lurking Elk    schedule 17.12.2016    source источник


Ответы (2)


Вам нужно закрыть сервер из другого потока, потому что serverSocket.accept(); будет блокироваться

Взгляните на: Прервать метод принятия и закрыть сервер

person Xephi    schedule 17.12.2016
comment
Его вопрос был: правильно ли завершать работу ServerSocket? Также я просто добавляю несколько аргументов, чтобы сказать «да», это ^_^ - person Xephi; 18.12.2016

Расширение ответа Xephi:

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

Что ж, не нужно вызывать the ServerSocket.close() из другого потока, но это, безусловно, рекомендуемый подход.

Это именно то, что он уже делает. - пользователь 207421

Нет это не так. Что делает OP, так это сбрасывает флаг serverRuns в другом потоке и периодически проверяет этот флаг в основном потоке Server с помощью тайм-аута сокета для вызова accept(); Я бы назвал это довольно уродливым.

При рекомендуемом подходе Server будет выглядеть так:

    Server()
    {
        try
        {
            serverSocket = new ServerSocket(PORT);
            (new Control(this)).start(); // Takes commands while working
            while (true)
            {
                Socket clientSocket = serverSocket.accept();
                …
            }
        } catch (SocketException e) { System.out.println("Server stopped"); }
          catch (IOException e)     { e.printStackTrace(); }
    }

    public void stopServer() throws IOException
    {
        serverSocket.close();
    }

а цикл Control можно упростить следующим образом:

        while (true)
        {
            String key = keyboard.nextLine().toLowerCase();
            switch (key)
            {
                case "close":
                    activeServer.stopServer();
                    return;
            }
        }
person Armali    schedule 14.11.2018