Даже если ваш сервер не «получает» от клиента, неблокирующее чтение на клиентском сокете скажет вам, что либо нечего читать (как вы ожидаете), либо что клиент отключился.
Если вы используете 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
, чтобы поймать дискотеку при записи.