Когда вы создаете сокет, сначала установите время ожидания:
private int timeout = 10000;
private int maxTimeout = 25000;
clientSocket.setSoTimeout(timeout);
При этом, если время чтения истекло, вы получите java.net.SocketTimeoutException
(который вы должны поймать). Таким образом, вы можете сделать что-то вроде этого, предполагая, что вы ранее установили SO_TIMEOUT, как показано выше, и предполагая, что сердцебиение всегда будет получать ответ от удаленной системы:
volatile long lastReadTime;
try {
bufferedReader.read();
lastReadTime = System.currentTimeMillis();
} catch (SocketTimeoutException e) {
if (!isConnectionAlive()) {
logger.info("CONNECTION TERMINATED!");
clientSocket.close();
setUpSocket(); //sets up the server to reconnect to the client
} else {
sendHeartBeat(); //Send a heartbeat to the client
}
}
public boolean isConnectionAlive() {
return System.currentTimeMillis() - lastReadTime < maxTimeout;
}
Обычный способ справиться с этим - установить тайм-аут на какое-то число (скажем, 10 секунд), а затем отслеживать последний раз, когда вы успешно читали из сокета. Если истекло время ожидания в 2,5 раза, откажитесь от клиента и закройте сокет (на всякий случай отправив пакет FIN на другую сторону).
Если сердцебиение не получит какой-либо ответ от удаленной системы, но это всего лишь способ в конечном итоге сгенерировать IOException раньше, когда соединение оборвется, тогда вы можете сделать это (при условии, что sendHeartBeat сам не скинет IOException):
try {
if (bufferedReader.read() == -1) {
logger.info("CONNECTION TERMINATED with EOF!");
resetConnection();
}
} catch (SocketTimeoutException e) {
// This just means our read timed out ... the socket is still good
sendHeartBeat(); //Send a heartbeat to the client
} catch (IOException e) {
logger.info("CONNECTION TERMINATED with Exception " + e.getMessage());
resetConnection();
}
....
private void resetConnection() {
clientSocket.close();
setUpSocket(); //sets up the server to reconnect to the client
}