Suggerimento Java 18: implementazione di una funzione di timeout per JDK 1.0.2 DatagramSocket

Se hai sviluppato un'applicazione Java che utilizza il socket Datagram per inviare e ricevere messaggi, potresti aver riscontrato la necessità di implementare una funzionalità di timeout per sbloccare il DatagramSocketmetodo di ricezione. Senza una funzione di timeout, l'applicazione si bloccherebbe fino a quando non riceve un messaggio e, poiché la consegna di Datagram non è garantita, l'applicazione potrebbe bloccarsi per un tempo molto lungo. Questo suggerimento Java descriverà una tecnica per il timeout e lo sblocco del DatagramSocketmetodo di ricezione.

Probabilmente hai già intuito che questa tecnica utilizzerà i thread. La programmazione dei thread in Java è abbastanza divertente. Lo si potrebbe paragonare alle gioie dello sci al Lago Tahoe o della vela vicino alla costa di Santa Cruz. (OK, forse non è così divertente, ma è comunque molto divertente!)

Quando si considera un metodo per realizzare la funzione di timeout, forse il primo e più ovvio schema che viene in mente è di posizionare la funzionalità di ricezione di DatagramSocket in un thread separato e quindi avviare un altro thread come timer che, alla scadenza, ucciderebbe thread se è ancora vivo. Anche se questo metodo funzionerà, probabilmente non è il modo più grazioso per eseguire l'operazione.

Invece di uccidere un thread bloccato sul metodo di ricezione, volevo una soluzione più graziosa, una che avrebbe sbloccato il metodo di ricezione. Per fare ciò, avevo bisogno di un thread in grado di inviare un messaggio di datagramma al thread di ricezione per sbloccare il thread di ricezione dopo che era scaduto un periodo di timeout. Il thread di timeout viene implementato come una propria classe e il thread di ricezione crea un'istanza della classe di timeout appena prima del blocco sul metodo di ricezione. Il codice seguente mostra l'implementazione della classe di timeout. Si noti che, per brevità, viene omessa la gestione delle eccezioni.

import java.io. *; import java.net. *; import java.lang. *; la classe pubblica DatagramWatchdogTimer implementa Runnable {DatagramWatchdogTimer (int timeoutSeconds) genera SocketException {timeout = timeoutSeconds; socket = nuovo DatagramSocket (); datagramPort = socket.getLocalPort (); Thread thisThread = new Thread (this); thisThread.start (); } public int getPort () {return datagramPort; } public void run () {// crea un messaggio di risposta standard che indica // il messaggio proviene da DatagramWatchdogTimer // nel mio caso, uno zero è sufficiente. String replyStr = new Integer (0) .toString (); byte [] replyBuf = nuovo byte [replyStr.length ()]; replyStr.getBytes (0, replyStr.length (), replyBuff, 0); int replyLength = replyStr.length (); // riceve un messaggio dal thread ricevente. // questo è necessario in modo da sapere come rispedirgli il // messaggio di sblocco.byte [] buffer = new bute [128]; Pacchetto DatagramPacket = nuovo DatagramPacket (buffer, buffer.length); socket.receive (packet); // attende il numero di secondi di timeout e quindi invia un messaggio di sblocco // indietro. Thread.sleep (timeout * 1000); int requestorPort = packet.getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = new DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = new DatagramSocket (); sendSocket.send (sendPacket); } private int timeout; private int datagramPort; presa DatagramSocket privata; }getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = new DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = new DatagramSocket (); sendSocket.send (sendPacket); } private int timeout; private int datagramPort; presa DatagramSocket privata; }getPort (); InetAddress requestorAddress = packet.getAddress (); DatagramPacket sendPacket = new DatagramPacket (replyBuff, replyLength, requestorAddress, requestorPort); DatagramSocket sendSocket = new DatagramSocket (); sendSocket.send (sendPacket); } private int timeout; private int datagramPort; presa DatagramSocket privata; }

Come accennato in precedenza, ogni volta che la tua applicazione ha bisogno di ricevere un messaggio di datagramma, può creare un'istanza della DatagramWatchdogTimerclasse per impostare un periodo di timeout. Se l'applicazione non riceve un messaggio reale entro timeout secondi, si sbloccherà ricevendo un messaggio di sblocco dalla DatagramWatchdogTimerclasse.

Ecco un esempio:

// codice applicazione int timeoutSeconds = 5; InetAddress myAddress = InetAddress.getByName (""); // crea un'istanza della classe timer DatagramWatchdogTimer wdTimer = new DatagramWatchdogTimer (timeoutSeconds); int wdPort = wdTimer.getPort (); // invia un messaggio a wdTimer per avviare il timer // msgBuff può essere quello che vuoi. String msgString = new String ("time me"); byte [] msgBuff = nuovo byte [msgString.length ()]; msgString.getBytes (0, msgString.length (), msgBuff, 0); DatagramSocket socket = nuovo DatagramSocket (); DatagramPacket wdPacket = nuovo DatagramPacket (msgBuff, msgLength, myAddress, wdPort); socket.send (wdPacket); // ora puoi leggere dal socket e avere la certezza // che bloccherai solo per timeoutSeconds. byte [] buffer = nuovo byte [1024]; Pacchetto DatagramPacket = nuovo Pacchetto Datagramma (buffer,buffer.length); socket.receive (packet); if (myAddress.equals (packet.getAddress) == true) {// ha ricevuto il messaggio dall'oggetto timer} else {// ha ricevuto un messaggio reale}

Quando si utilizza questa tecnica, assicurarsi di utilizzare lo stesso DatagramSocket sia per l'invio all'oggetto DatagramWatchdogTimer sia per la ricezione di datagrammi. Ciò garantisce che l'oggetto DatagramWatchdogTimer sappia dove inviare il messaggio di sblocco. Inoltre, nel codice di esempio mostrato sopra una porta allocata dinamicamente è stata utilizzata creando un'istanza di DatagramSocket () senza argomenti. Funzionerebbe anche utilizzando una porta ben nota di tua scelta come DatagramSocket (8000). Infine, potresti volere che l'oggetto timer invii più di un messaggio di sblocco, solo per aumentare le possibilità che venga ricevuto dall'applicazione. Questo non dovrebbe essere un problema poiché l'oggetto timer è in esecuzione come thread sulla stessa macchina dell'applicazione.

Albert Lopez è stato membro dello staff tecnico di Sun Microsystems dal 1989 al 1995. Recentemente è entrato a far parte dello staff dei sistemi informativi presso il Chicago Board of Trade, dove è un membro principale del team di sviluppo Java che sta sviluppando la prossima generazione sistema di commercio elettronico che utilizza Java.

Questa storia, "Java Tip 18: Implementing a timeout feature for the JDK 1.0.2 DatagramSocket" è stata originariamente pubblicata da JavaWorld.