Programmering

Java Tip 18: Implementering af en timeout-funktion til JDK 1.0.2 DatagramSocket

Hvis du har udviklet en Java-applikation, der bruger Datagram-stikket til at sende og modtage meddelelser, har du muligvis stødt på behovet for at implementere en timeout-funktion for at fjerne blokeringen af DatagramSocket modtage metode. Uden en timeout-funktion vil din applikation blokere, indtil den modtager en besked, og da levering af Datagram ikke er garanteret, kan din applikation blokere i meget lang tid. Dette Java-tip vil beskrive en teknik til timing af og blokering af DatagramSocket modtage metode.

Du har sandsynligvis allerede gættet, at denne teknik vil gøre brug af tråde. Trådprogrammering i Java er ret behageligt. Man kunne sammenligne det med glæden ved skiløb ved Lake Tahoe eller at sejle nær Santa Cruz-kysten. (OK, måske er det ikke at behageligt, men det er stadig meget sjovt!)

Når man overvejer en metode til at udføre timeout-funktionen, er måske den første og mest oplagte ordning, der kommer til at tænke på, at placere DatagramSocket-modtagefunktionaliteten i en separat tråd og derefter starte endnu en tråd som en timer, der ved udløb dræber modtagelsen tråd, hvis den stadig er i live. Mens denne metode fungerer, er det sandsynligvis ikke den mest yndefulde måde at udføre opgaven på.

I stedet for at dræbe en tråd, der er blokeret i modtagemetoden, ønskede jeg en mere yndefuld løsning - en, der ville blokere modtagemetoden. For at opnå dette havde jeg brug for en tråd, der var i stand til at sende en datagram-meddelelse til den modtagende tråd for at fjerne blokeringen af ​​den modtagende tråd, efter at en timeout-periode var udløbet. Timeouttråden implementeres som sin egen klasse, og den modtagende tråd opretter en forekomst af timeoutklassen lige før den blokerer modtagemetoden. Den følgende kode viser timeoutklassens implementering. Bemærk, at undtagelseshåndtering for kortfattethed udelades.

import java.io. *; import java.net. *; import java.lang. *; offentlig klasse DatagramWatchdogTimer implementerer Runnable {DatagramWatchdogTimer (int timeoutSeconds) kaster SocketException {timeout = timeoutSeconds; sokkel = ny DatagramSocket (); datagramPort = socket.getLocalPort (); Tråd thisThread = ny tråd (denne); thisThread.start (); } public int getPort () {return datagramPort; } public void run () {// opret en standard svarmeddelelse, der angiver // meddelelsen kom fra DatagramWatchdogTimer // i mit tilfælde er nul nok. String replyStr = nyt heltal (0) .toString (); byte [] replyBuf = ny byte [replyStr.length ()]; replyStr.getBytes (0, replyStr.length (), replyBuff, 0); int replyLength = replyStr.length (); // modtage en besked fra den modtagende tråd. // dette er nødvendigt, så vi ved, hvordan vi sender unblocking // -beskeden tilbage til den. byte [] buffer = ny bute [128]; DatagramPacket-pakke = ny DatagramPacket (buffer, buffer.length); socket.receive (pakke); // vent timeout antal sekunder, og send derefter en blokering // besked tilbage. Thread.sleep (timeout * 1000); int requestorPort = packet.getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = ny DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = ny DatagramSocket (); sendSocket.send (sendPacket); } privat int timeout; privat int datagramPort; privat DatagramSocket-stik; } 

Som nævnt ovenfor, når din applikation har brug for at modtage en datagram-besked, kan den oprette en forekomst af DatagramWatchdogTimer klasse for at indstille en timeout-periode. Hvis applikationen ikke modtager en reel besked inden for timeout sekunder, vil den fjerne blokeringen ved at modtage en blokering af beskeden fra DatagramWatchdogTimer klasse.

Her er et eksempel:

// applikationskode int timeoutSeconds = 5; InetAddress myAddress = InetAddress.getByName (""); // opret en forekomst af timerklassen DatagramWatchdogTimer wdTimer = ny DatagramWatchdogTimer (timeoutSeconds); int wdPort = wdTimer.getPort (); // send en besked til wdTimer for at få timeren i gang // msgBuff kan være hvad du vil. Streng msgString = ny streng ("tid mig"); byte [] msgBuff = ny byte [msgString.length ()]; msgString.getBytes (0, msgString.length (), msgBuff, 0); DatagramSocket-sokkel = ny DatagramSocket (); DatagramPacket wdPacket = ny DatagramPacket (msgBuff, msgLength, myAddress, wdPort); socket.send (wdPacket); // nu kan du læse fra stikkontakten og have en vis sikkerhed // at du kun blokerer for timeoutSeconds. byte [] buffer = ny byte [1024]; DatagramPacket-pakke = ny DatagramPacket (buffer, buffer.length); socket.receive (pakke); hvis (myAddress.equals (packet.getAddress) == true) {// modtaget besked fra timer-objekt} ellers {// modtaget en reel besked} 

Når du bruger denne teknik, skal du sørge for at bruge den samme DatagramSocket til både afsendelse til DatagramWatchdogTimer-objektet og til modtagelse af datagrammer. Dette sikrer, at DatagramWatchdogTimer-objektet ved, hvor den blokerende meddelelse skal sendes. Også i prøvekoden vist ovenfor blev en dynamisk tildelt port brugt ved at starte DatagramSocket () uden nogen argumenter. Det fungerer også ved hjælp af en velkendt port efter eget valg som DatagramSocket (8000). Endelig vil du muligvis have, at timerobjektet sender mere end en blokering af besked - bare for at øge chancerne for, at det bliver modtaget af applikationen. Dette burde ikke være et problem, da timerobjektet kører som en tråd på den samme maskine som applikationen.

Albert Lopez var medlem af det tekniske personale hos Sun Microsystems fra 1989 til 1995. Han er for nylig ansat i informationssystemets personale på Chicago Board of Trade, hvor han er et ledende medlem af Java-udviklingsteamet, der udvikler den næste generation elektronisk handelssystem ved hjælp af Java.

Denne historie, "Java Tip 18: Implementering af en timeout-funktion til JDK 1.0.2 DatagramSocket" blev oprindeligt udgivet af JavaWorld.