Java-Tipp 18: Implementieren einer Timeout-Funktion für das JDK 1.0.2 DatagramSocket

Wenn Sie eine Java-Anwendung entwickelt haben, die den Datagramm-Socket zum Senden und Empfangen von Nachrichten verwendet, müssen Sie möglicherweise eine Timeout-Funktion implementieren, um die DatagramSocketEmpfangsmethode zu entsperren . Ohne eine Zeitüberschreitungsfunktion würde Ihre Anwendung blockieren, bis sie eine Nachricht empfängt. Da die Zustellung von Datagramm nicht garantiert ist, kann Ihre Anwendung sehr lange blockieren. Dieser Java-Tipp beschreibt eine Technik zum Zeitlimitieren und Entsperren der DatagramSocketEmpfangsmethode.

Sie haben wahrscheinlich bereits vermutet, dass diese Technik Threads verwendet. Die Thread-Programmierung in Java macht sehr viel Spaß. Man könnte es mit den Freuden des Skifahrens am Lake Tahoe oder des Segelns in der Nähe der Küste von Santa Cruz vergleichen. (OK, es ist vielleicht nicht , dass Spaß, aber es ist immer noch eine Menge Spaß!)

Wenn Sie über eine Methode nachdenken, um die Timeout-Funktion zu erreichen, besteht das erste und naheliegendste Schema darin, die DatagramSocket-Empfangsfunktion in einem separaten Thread zu platzieren und dann einen weiteren Thread als Timer zu starten, der nach Ablauf den Empfang abbricht Thread, wenn es noch lebt. Obwohl diese Methode funktioniert, ist sie wahrscheinlich nicht die eleganteste Art, die Aufgabe zu erfüllen.

Anstatt einen Thread zu beenden, der bei der Empfangsmethode blockiert ist, wollte ich eine elegantere Lösung - eine, die die Empfangsmethode entsperrt. Um dies zu erreichen, benötigte ich einen Thread, der eine Datagrammnachricht an den empfangenden Thread senden konnte, um den empfangenden Thread nach Ablauf einer Zeitüberschreitung zu entsperren. Der Timeout-Thread wird als eigene Klasse implementiert, und der empfangende Thread erstellt unmittelbar vor dem Blockieren der Empfangsmethode eine Instanz der Timeout-Klasse. Der folgende Code zeigt die Implementierung der Timeout-Klasse. Beachten Sie, dass der Kürze halber die Ausnahmebehandlung weggelassen wird.

import java.io. *; import java.net. *; import java.lang. *; öffentliche Klasse DatagramWatchdogTimer implementiert Runnable {DatagramWatchdogTimer (int timeoutSeconds) löst SocketException aus {timeout = timeoutSeconds; socket = new DatagramSocket (); datagramPort = socket.getLocalPort (); Thread thisThread = neuer Thread (this); thisThread.start (); } public int getPort () {return datagramPort; } public void run () {// Erstelle eine Standardantwortnachricht, die angibt, // dass die Nachricht vom DatagramWatchdogTimer stammt // in meinem Fall reicht eine Null aus. String replyStr = new Integer (0) .toString (); Byte [] replyBuf = neues Byte [replyStr.length ()]; replyStr.getBytes (0, replyStr.length (), replyBuff, 0); int replyLength = replyStr.length (); // eine Nachricht vom empfangenden Thread empfangen. // Dies ist notwendig, damit wir wissen, wie die // Entsperrungsnachricht an sie zurückgesendet werden kann.Byte [] Puffer = neues Bute [128]; DatagramPacket-Paket = neues DatagramPacket (buffer, buffer.length); socket.receive (Paket); // Wartezeit in Sekunden und sende dann eine // Entsperrungsnachricht zurück. Thread.sleep (Timeout * 1000); int requestorPort = packet.getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = neues DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = new DatagramSocket (); sendSocket.send (sendPacket); } private int timeout; private int datagramPort; privater DatagramSocket-Socket; }}getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = neues DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = new DatagramSocket (); sendSocket.send (sendPacket); } private int timeout; private int datagramPort; privater DatagramSocket-Socket; }}getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = neues DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = new DatagramSocket (); sendSocket.send (sendPacket); } private int timeout; private int datagramPort; privater DatagramSocket-Socket; }}

Wie oben erwähnt, kann Ihre Anwendung immer dann, wenn sie eine Datagrammnachricht empfangen muss, eine Instanz der DatagramWatchdogTimerKlasse erstellen , um eine Zeitüberschreitungsperiode festzulegen. Wenn die Anwendung innerhalb von Sekunden keine echte Nachricht empfängt, wird die Blockierung aufgehoben, indem eine Entsperrnachricht von der DatagramWatchdogTimerKlasse empfangen wird .

Hier ist ein Beispiel:

// Anwendungscode int timeoutSeconds = 5; InetAddress myAddress = InetAddress.getByName (""); // eine Instanz der Timer-Klasse erstellen DatagramWatchdogTimer wdTimer = new DatagramWatchdogTimer (timeoutSeconds); int wdPort = wdTimer.getPort (); // Sende eine Nachricht an wdTimer, um den Timer zu starten // msgBuff kann alles sein, was du willst. String msgString = neuer String ("time me"); Byte [] msgBuff = neues Byte [msgString.length ()]; msgString.getBytes (0, msgString.length (), msgBuff, 0); DatagramSocket socket = new DatagramSocket (); DatagramPacket wdPacket = neues DatagramPacket (msgBuff, msgLength, myAddress, wdPort); socket.send (wdPacket); // Jetzt können Sie aus dem Socket lesen und // sicher sein, dass Sie nur für timeoutSeconds blockieren. Byte [] Puffer = neues Byte [1024]; DatagramPacket-Paket = neues DatagramPacket (Puffer,buffer.length); socket.receive (Paket); if (myAddress.equals (packet.getAddress) == true) {// Nachricht vom Timer-Objekt empfangen} else {// echte Nachricht empfangen}

Stellen Sie bei Verwendung dieser Technik sicher, dass Sie denselben DatagramSocket sowohl zum Senden an das DatagramWatchdogTimer-Objekt als auch zum Empfangen von Datagrammen verwenden. Dadurch wird sichergestellt, dass das DatagramWatchdogTimer-Objekt weiß, wohin die Entsperrungsnachricht gesendet werden soll. In dem oben gezeigten Beispielcode wurde außerdem ein dynamisch zugewiesener Port verwendet, indem DatagramSocket () ohne Argumente instanziiert wurde. Es würde auch mit einem bekannten Port Ihrer Wahl wie DatagramSocket (8000) funktionieren. Schließlich möchten Sie möglicherweise, dass das Timer-Objekt mehr als eine Entsperrungsnachricht sendet, um die Wahrscheinlichkeit zu erhöhen, dass sie von der Anwendung empfangen wird. Dies sollte kein Problem sein, da das Timer-Objekt als Thread auf demselben Computer wie die Anwendung ausgeführt wird.

Albert Lopez war von 1989 bis 1995 technischer Mitarbeiter bei Sun Microsystems. Kürzlich wechselte er zu den Mitarbeitern für Informationssysteme des Chicago Board of Trade, wo er als leitender Mitarbeiter des Java-Entwicklungsteams tätig ist, das die nächste Generation entwickelt elektronisches Handelssystem mit Java.

Diese Geschichte "Java-Tipp 18: Implementieren einer Timeout-Funktion für das JDK 1.0.2 DatagramSocket" wurde ursprünglich von JavaWorld veröffentlicht.