250 lines
8.0 KiB
HTML
250 lines
8.0 KiB
HTML
|
|
|
|
|
|
<!DOCTYPE html>
|
|
<html id="htmlId">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
|
<title>Coverage Report > HeartbeatHandler</title>
|
|
<style type="text/css">
|
|
@import "../../css/coverage.css";
|
|
@import "../../css/idea.min.css";
|
|
</style>
|
|
<script type="text/javascript" src="../../js/highlight.min.js"></script>
|
|
<script type="text/javascript" src="../../js/highlightjs-line-numbers.min.js"></script>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="content">
|
|
<div class="breadCrumbs">
|
|
Current scope: <a href="../../index.html">all classes</a>
|
|
<span class="separator">|</span>
|
|
<a href="../index.html">it.polimi.ingsw.gc14.Network.TCP.Server</a>
|
|
</div>
|
|
|
|
<h1>Coverage Summary for Class: HeartbeatHandler (it.polimi.ingsw.gc14.Network.TCP.Server)</h1>
|
|
|
|
<table class="coverageStats">
|
|
<tr>
|
|
<th class="name">Class</th>
|
|
<th class="coverageStat
|
|
">
|
|
Class, %
|
|
</th>
|
|
<th class="coverageStat
|
|
">
|
|
Method, %
|
|
</th>
|
|
<th class="coverageStat
|
|
">
|
|
Branch, %
|
|
</th>
|
|
<th class="coverageStat
|
|
">
|
|
Line, %
|
|
</th>
|
|
</tr>
|
|
<tr>
|
|
<td class="name">HeartbeatHandler</td>
|
|
<td class="coverageStat">
|
|
<span class="percent">
|
|
0%
|
|
</span>
|
|
<span class="absValue">
|
|
(0/1)
|
|
</span>
|
|
</td>
|
|
<td class="coverageStat">
|
|
<span class="percent">
|
|
0%
|
|
</span>
|
|
<span class="absValue">
|
|
(0/5)
|
|
</span>
|
|
</td>
|
|
<td class="coverageStat">
|
|
<span class="percent">
|
|
0%
|
|
</span>
|
|
<span class="absValue">
|
|
(0/8)
|
|
</span>
|
|
</td>
|
|
<td class="coverageStat">
|
|
<span class="percent">
|
|
0%
|
|
</span>
|
|
<span class="absValue">
|
|
(0/28)
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<br/>
|
|
<br/>
|
|
|
|
|
|
<pre>
|
|
<code class="sourceCode" id="sourceCode"> package it.polimi.ingsw.gc14.Network.TCP.Server;
|
|
|
|
import java.io.*;
|
|
import java.net.*;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
import java.util.concurrent.TimeUnit;
|
|
import it.polimi.ingsw.gc14.Network.NetworkConfig;
|
|
|
|
/**
|
|
* Handles the heartbeat communication associated with a TCP client.
|
|
*
|
|
* <p>This component listens for heartbeat {@code PING} messages from the client,
|
|
* replies with {@code PONG} messages, and periodically checks whether the client
|
|
* has remained silent for too long. If a timeout or communication error occurs,
|
|
* both the heartbeat connection and the main client connection are disconnected.
|
|
*/
|
|
public class HeartbeatHandler implements Runnable {
|
|
/** Username of the client associated with this heartbeat connection. */
|
|
private final String username;
|
|
/** Dedicated socket used solely for heartbeat ping/pong exchange. */
|
|
private final Socket socket;
|
|
/** Input stream of {@link #socket} used to receive {@code PING} bytes from the client. */
|
|
private final InputStream in;
|
|
/** Output stream of {@link #socket} used to send {@code PONG} bytes back to the client. */
|
|
private final OutputStream out;
|
|
|
|
/**
|
|
* Byte value representing a heartbeat ping message.
|
|
*/
|
|
private static final int PING = 1;
|
|
|
|
/**
|
|
* Byte value representing a heartbeat pong response.
|
|
*/
|
|
private static final int PONG = 2;
|
|
|
|
/**
|
|
* Main client handler associated with this heartbeat connection.
|
|
*/
|
|
private final ClientHandler mainHandler;
|
|
|
|
/**
|
|
* Timestamp of the last received heartbeat message.
|
|
*/
|
|
<b class="nc"> private volatile long lastReceivedTime = System.currentTimeMillis();</b>
|
|
|
|
/**
|
|
* Indicates whether the heartbeat handler is still active.
|
|
*/
|
|
<b class="nc"> private volatile boolean running = true;</b>
|
|
|
|
|
|
/**
|
|
* Executor used to periodically check heartbeat timeouts.
|
|
*/
|
|
<b class="nc"> private final ScheduledExecutorService watchdog =</b>
|
|
<b class="nc"> Executors.newSingleThreadScheduledExecutor();</b>
|
|
|
|
/**
|
|
* Constructs a heartbeat handler for the specified client.
|
|
*
|
|
* @param username the username of the connected client.
|
|
* @param socket the socket dedicated to heartbeat communication.
|
|
* @param mainHandler the main client handler associated with the same player.
|
|
* @throws IOException if the input or output stream cannot be obtained from the socket.
|
|
*/
|
|
public HeartbeatHandler(String username, Socket socket, ClientHandler mainHandler)
|
|
<b class="nc"> throws IOException {</b>
|
|
<b class="nc"> this.username = username;</b>
|
|
<b class="nc"> this.socket = socket;</b>
|
|
<b class="nc"> this.mainHandler = mainHandler;</b>
|
|
<b class="nc"> this.in = socket.getInputStream();</b>
|
|
<b class="nc"> this.out = socket.getOutputStream();</b>
|
|
}
|
|
|
|
/**
|
|
* Starts the heartbeat listening loop.
|
|
*
|
|
* <p>The method activates the watchdog task, then waits for incoming heartbeat
|
|
* messages. When a {@code PING} is received, the last-received timestamp is
|
|
* updated and a {@code PONG} response is sent back to the client.
|
|
* If the stream is closed or an I/O error occurs, the client is disconnected.
|
|
*/
|
|
@Override
|
|
public void run() {
|
|
<b class="nc"> startWatchdog();</b>
|
|
try {
|
|
<b class="nc"> while (running) {</b>
|
|
<b class="nc"> int b = in.read();</b>
|
|
<b class="nc"> if (b == -1) {</b>
|
|
<b class="nc"> disconnect();</b>
|
|
break;
|
|
}
|
|
<b class="nc"> if (b == PING) {</b>
|
|
<b class="nc"> lastReceivedTime = System.currentTimeMillis();</b>
|
|
<b class="nc"> out.write(PONG);</b>
|
|
<b class="nc"> out.flush();</b>
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
<b class="nc"> disconnect();</b>
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Starts the periodic watchdog task that detects heartbeat timeouts.
|
|
*
|
|
* <p>If no heartbeat message is received within the configured silence threshold,
|
|
* the associated client is disconnected.
|
|
*/
|
|
private void startWatchdog() {
|
|
<b class="nc"> watchdog.scheduleAtFixedRate(() -> {</b>
|
|
<b class="nc"> if (System.currentTimeMillis() - lastReceivedTime > NetworkConfig.SILENCE_THRESHOLD_MS) {</b>
|
|
<b class="nc"> System.out.println("Heartbeat timeout: " + username);</b>
|
|
<b class="nc"> disconnect();</b>
|
|
}
|
|
}, 1, 1, TimeUnit.SECONDS);
|
|
}
|
|
|
|
/**
|
|
* Disconnects the heartbeat channel and the associated main client connection.
|
|
*
|
|
* <p>The handler is stopped, the watchdog task is terminated, the main
|
|
* {@link ClientHandler} is disconnected, and the heartbeat socket is closed.
|
|
*/
|
|
private synchronized void disconnect() {
|
|
<b class="nc"> running = false;</b>
|
|
<b class="nc"> watchdog.shutdownNow();</b>
|
|
<b class="nc"> mainHandler.disconnect();</b>
|
|
<b class="nc"> try { socket.close(); } catch (IOException ignored) {}</b>
|
|
}
|
|
}
|
|
</code>
|
|
</pre>
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
(function() {
|
|
var msie = false, msie9 = false;
|
|
/*@cc_on
|
|
msie = true;
|
|
@if (@_jscript_version >= 9)
|
|
msie9 = true;
|
|
@end
|
|
@*/
|
|
|
|
if (!msie || msie && msie9) {
|
|
hljs.highlightAll()
|
|
hljs.initLineNumbersOnLoad();
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
<div class="footer">
|
|
|
|
<div style="float:right;">generated on 2026-06-19 22:53</div>
|
|
</div>
|
|
</body>
|
|
</html>
|