Проверка отключения клиента на сервере Java TCP - только вывод - PullRequest
4 голосов
/ 10 марта 2011

У меня есть сервер Java TCP, который, когда клиент подключается к нему, выводит сообщение клиенту каждые 30 секунд.Строгое требование, чтобы клиент не отправлял никаких сообщений на сервер, и чтобы сервер не отправлял клиенту никаких данных, кроме 30-секундных интервальных сообщений.сервер не поймет этого, пока в следующий раз не попытается написать клиенту.Таким образом, серверу может потребоваться до 30 секунд для распознавания разъединения.

Я хочу проверять разъединение каждые несколько секунд без необходимости ждать, но я не уверен, как это сделатьчто а) сервер не получает от клиента и б) сервер не может отправлять какие-либо другие данные.Кто-нибудь сможет пролить свет на это?Спасибо.

Ответы [ 2 ]

9 голосов
/ 10 марта 2011

Даже если ваш сервер не «получает» от клиента, неблокирующее чтение на клиентском сокете скажет вам, что либо нечего читать (как вы ожидаете), либо что клиент отключился.

Если вы используете NIO, вы можете просто использовать неблокирующую петлю Selector (с неблокирующими сокетами) и писать только на своих 30-секундных отметках.Если SelectionKey доступен для чтения, а чтение SocketChannel возвращает -1, вы знаете, что клиент отключился.

РЕДАКТИРОВАТЬ: Другой подход с блокировкой заключается в простом выборе с 30-секундным таймаутом.Любое отключение клиента приведет к тому, что select вернется, и вы узнаете, какие из них через набор чтения.Еще одна вещь, которую вам нужно сделать, это отслеживать, как долго вы были заблокированы в выборе, чтобы выяснить, когда делать ваши записи на 30-секундной отметке (установка времени ожидания для следующего выбора в дельту).

Большое редактирование: После разговора с Мином ниже, предлагая полный пример:

public static void main(String[] args) throws IOException {

    ServerSocket serverSocket = null;
    try {
        serverSocket = new ServerSocket(4444);
    } catch (IOException e) {
        System.err.println("Could not listen on port: 4444.");
        System.exit(1);
    }

    Socket clientSocket = null;
    try {
        clientSocket = serverSocket.accept();
    } catch (IOException e) {
        System.err.println("Accept failed.");
        System.exit(1);
    }

    // Set a 1 second timeout on the socket
    clientSocket.setSoTimeout(1000);

    PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
    BufferedReader in = new BufferedReader(
            new InputStreamReader(
            clientSocket.getInputStream()));

    long myNextOutputTime = System.currentTimeMillis() + 30000;

    String inputLine = null;
    boolean connected = true;
    while (connected)
    {
        try {
            inputLine = in.readLine();
            if (inputLine == null)
            {
                System.out.println("Client Disconnected!");
                connected = false;
            }
        }
        catch(java.net.SocketTimeoutException e)
        {
            System.out.println("Timed out trying to read from socket");
        }

        if (connected && (System.currentTimeMillis() - myNextOutputTime > 0))
        {
            out.println("My Message to the client");
            myNextOutputTime += 30000;
        }


    }

    out.close();
    in.close();
    clientSocket.close();
    serverSocket.close();
}

Стоит отметить, что PrintWriter действительно удаляет вас отфактический сокет, и вы не собираетесь перехватывать разъединение сокета при записи (оно никогда не вызовет исключение, вы должны вручную проверить его с помощью checkError()). Вместо этого вы можете перейти на BufferedWriter (требуется использование flush(), чтобы выдвинуть вывод) и обрабатывать его как BufferedReader, чтобы поймать дискотеку при записи.

1 голос
/ 10 марта 2011

Если вы управляете несколькими клиентами, то, я думаю, вы бы использовали неблокирующие сокеты (если нет, то рассмотрите возможность использования неблокирующих сокетов). Вы можете использовать Selector для мониторинга всех подключенных сокетов, чтобы проверить, доступны ли они для чтения или записи, или в этом сокете есть какая-то Ошибка. Когда какой-либо клиент отключается, ваш селектор отметит этот сокет и вернется. Для получения дополнительной помощи Google "Функция выбора гнезда"

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