Astuce Java 18: Implémentation d'une fonction de délai d'expiration pour le DatagramSocket JDK 1.0.2

Si vous avez développé une application Java qui utilise le socket Datagram pour envoyer et recevoir des messages, vous avez peut-être rencontré le besoin d'implémenter une fonction de délai d'expiration pour débloquer la DatagramSocketméthode de réception. Sans une fonction de délai d'expiration, votre application se bloquerait jusqu'à ce qu'elle reçoive un message, et comme la livraison du datagramme n'est pas garantie, votre application pourrait se bloquer pendant très longtemps. Cette astuce Java décrit une technique de temporisation et de déblocage de la DatagramSocketméthode de réception.

Vous avez probablement déjà deviné que cette technique utilisera des fils. La programmation de threads en Java est assez agréable. On pourrait le comparer aux joies de la glisse au lac Tahoe ou de la voile près de la côte de Santa Cruz. (OK, ce n'est peut-être pas si agréable, mais c'est toujours très amusant!)

Lorsque vous envisagez une méthode pour accomplir la fonction de délai d'expiration, le premier et le plus évident schéma qui me vient à l'esprit est peut-être de placer la fonctionnalité de réception DatagramSocket dans un thread séparé, puis de lancer un autre thread en tant que minuterie qui, à l'expiration, tuerait la réception. thread s'il est toujours en vie. Bien que cette méthode fonctionne, ce n'est probablement pas la manière la plus élégante d'accomplir la tâche.

Au lieu de tuer un thread qui est bloqué sur la méthode de réception, je voulais une solution plus gracieuse - une qui débloquerait la méthode de réception. Pour ce faire, j'avais besoin d'un thread capable d'envoyer un message de datagramme au thread de réception pour débloquer le thread de réception après l'expiration d'un délai. Le thread timeout est implémenté comme sa propre classe, et le thread récepteur crée une instance de la classe timeout juste avant le blocage sur la méthode de réception. Le code suivant montre l'implémentation de la classe timeout. Notez que, par souci de concision, la gestion des exceptions est omise.

import java.io. *; import java.net. *; import java.lang. *; la classe publique DatagramWatchdogTimer implémente Runnable {DatagramWatchdogTimer (int timeoutSeconds) jette SocketException {timeout = timeoutSeconds; socket = nouveau DatagramSocket (); datagramPort = socket.getLocalPort (); Thread thisThread = nouveau Thread (this); thisThread.start (); } public int getPort () {return datagramPort; } public void run () {// crée un message de réponse standard qui indique // que le message provient du DatagramWatchdogTimer // dans mon cas, un zéro suffit. String replyStr = new Integer (0) .toString (); byte [] replyBuf = nouvel octet [replyStr.length ()]; replyStr.getBytes (0, replyStr.length (), replyBuff, 0); int replyLength = replyStr.length (); // reçoit un message du thread de réception. // cela est nécessaire pour que nous sachions comment lui renvoyer le message de déblocage //.byte [] buffer = nouveau bute [128]; DatagramPacket packet = nouveau DatagramPacket (buffer, buffer.length); socket.receive (paquet); // attendez le nombre de secondes, puis renvoyez un // message de déblocage. Thread.sleep (timeout * 1000); int requestorPort = packet.getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = new DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = nouveau DatagramSocket (); sendSocket.send (sendPacket); } timeout int privé; private int datagramPort; socket DatagramSocket privé; }getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = new DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = nouveau DatagramSocket (); sendSocket.send (sendPacket); } timeout int privé; private int datagramPort; socket DatagramSocket privé; }getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = new DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = nouveau DatagramSocket (); sendSocket.send (sendPacket); } timeout int privé; private int datagramPort; socket DatagramSocket privé; }

Comme mentionné ci-dessus, chaque fois que votre application a besoin de recevoir un message de datagramme, elle peut créer une instance de la DatagramWatchdogTimerclasse pour définir un délai d'expiration. Si l'application ne reçoit pas de message réel dans le délai imparti, elle se débloquera en recevant un message de déblocage de la DatagramWatchdogTimerclasse.

Voici un exemple:

// code d'application int timeoutSeconds = 5; InetAddress myAddress = InetAddress.getByName (""); // crée une instance de la classe de minuterie DatagramWatchdogTimer wdTimer = new DatagramWatchdogTimer (timeoutSeconds); int wdPort = wdTimer.getPort (); // envoyer un message à wdTimer pour démarrer le minuteur // msgBuff peut être ce que vous voulez. String msgString = new String ("time me"); byte [] msgBuff = nouvel octet [msgString.length ()]; msgString.getBytes (0, msgString.length (), msgBuff, 0); Prise DatagramSocket = new DatagramSocket (); DatagramPacket wdPacket = nouveau DatagramPacket (msgBuff, msgLength, myAddress, wdPort); socket.send (wdPacket); // maintenant vous pouvez lire à partir du socket et avoir une certaine assurance // que vous ne bloquerez que pendant timeoutSeconds. byte [] buffer = nouvel octet [1024]; DatagramPacket packet = new DatagramPacket (tampon,buffer.length); socket.receive (paquet); if (myAddress.equals (packet.getAddress) == true) {// a reçu un message de l'objet timer} else {// a reçu un vrai message}

Lorsque vous utilisez cette technique, veillez à utiliser le même DatagramSocket pour l'envoi à l'objet DatagramWatchdogTimer et pour la réception de datagrammes. Cela garantit que l'objet DatagramWatchdogTimer sait où envoyer le message de déblocage. En outre, dans l'exemple de code ci-dessus, un port alloué dynamiquement a été utilisé en instanciant le DatagramSocket () sans aucun argument. Cela fonctionnerait également en utilisant un port bien connu de votre choix tel que DatagramSocket (8000). Enfin, vous souhaiterez peut-être que l'objet timer envoie plus d'un message de déblocage - juste pour augmenter les chances qu'il soit reçu par l'application. Cela ne devrait pas poser de problème car l'objet timer s'exécute en tant que thread sur la même machine que l'application.

Albert Lopez a été membre du personnel technique de Sun Microsystems de 1989 à 1995. Il a récemment rejoint le personnel des systèmes d'information du Chicago Board of Trade, où il est membre principal de l'équipe de développement Java qui développe la nouvelle génération système de trading électronique utilisant Java.

Cette histoire, "Astuce Java 18: Implémentation d'une fonction de délai d'expiration pour le JDK 1.0.2 DatagramSocket" a été publiée à l'origine par JavaWorld.