Contrairement à un client, pour faire un seveur, on doit utiliser un DatagramChannel
attaché à un port précis, préalablement communiqué aux clients.
Attachement sur le port 7777 (s'il est libre)
dc.bind(new InetSocketAddress(7777));
BindException
est levée.
Il est impossible de libérer le port en Java, il faut arrêter le serveur qui occupe le port.bind
prend un InetSocketAddress
et pas simplement un numéro de port, pourquoi ?Un serveur réagit toujours aux requêtes des clients. Il attend d'être contacté et n'initie jamais le contact.
La boucle d'un serveur est donc très simple :
Echo
ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); while (!Thread.interrupted()) { buffer.clear(); var sender = (InetSocketAddress) dc.receive(buffer); logger.info("Received " + buffer.position() + " bytes from " + sender.toString()); buffer.flip(); logger.info("Sending " + buffer.remaining() + " bytes from " + sender.toString()); dc.send(buffer, sender); }
Un protocole est stateless si la réponse à une requête d'un client ne dépend que de cette requête et pas de ses requêtes précédentes.
Tous les protocoles que nous avons vus pour l'instant (Echo, UpperCase, BetterUpperCase et IdUpperCase) étaient stateless.
Un protocole est statefull si la réponse à une requête d'un client dépend de ses précédentes requêtes.
Dans le protocole Count, le serveur répond à n'importe quelle requête du client par un paquet
contenant un long
en Big Endian qui donne le nombre de paquets reçus de ce client depuis le démarrage du serveur.
Ici, on considère qu'un client est identifié par le couple (adresse IP, port), i.e., son
InetSocketAddress
.
Pour un protocole statefull, le serveur va devoir mémoriser des informations sur les paquets reçus de chaque client.
Attention à ne pas mélanger les paquets venant des différents clients.
Le serveur maintient les informations des clients dans une HashMap<InetSocketAddress, ClientData>
ClientData
est une classe stockant les informations nécessaires.
Attention, il faut stocker le moins d'informations possible et mettre en place des mécanismes pour libérer la mémoire
occupée par les informations stockées dans la HashMap
.
Count
var receiveBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE); var sendBuffer = ByteBuffer.allocateDirect(Long.BYTES); var map = new HashMap<InetSocketAddress, Long>(); while (!Thread.interrupted()) { receiveBuffer.clear(); var sender = (InetSocketAddress) dc.receive(receiveBuffer); var nb = map.merge(sender, 1L, Long::sum); sendBuffer.clear(); sendBuffer.putLong(nb).flip(); dc.send(sendBuffer, sender); }