Съвет за Java 18: Внедряване на функция за изчакване за JDK 1.0.2 DatagramSocket

Ако сте разработили приложение на Java, което използва Datagram сокет за изпращане и получаване на съобщения, тогава може да сте се сблъскали с необходимостта да внедрите функция за изчакване, за да деблокирате DatagramSocketметода за получаване. Без функция за изчакване приложението ви ще блокира, докато не получи съобщение и тъй като доставката на Datagram не е гарантирана, приложението ви може да блокира наистина дълго време. Този Java съвет ще опише техника за изчакване и деблокиране на DatagramSocketметода за получаване.

Вероятно вече сте се досетили, че тази техника ще използва нишки. Програмирането на нишки в Java е доста приятно. Може да се сравни с радостите от карането на ски при езерото Тахо или от плаването близо до брега на Санта Круз. (Добре, може би не е толкова приятно, но все пак е много забавно!)

Когато се обмисля метод за постигане на функцията за изчакване, може би първата и най-очевидна схема, която идва на ум, е да се постави функцията за получаване на DatagramSocket в отделна нишка и след това да се стартира друга нишка като таймер, който при изтичане ще убие получаването нишка, ако все още е жива. Въпреки че този метод ще работи, вероятно не е най-изящният начин за изпълнение на задачата.

Вместо да убия нишка, която е блокирана в метода за получаване, исках по-изящно решение - такова, което да деблокира метода за получаване. За да постигна това, се нуждаех от нишка, която можеше да изпрати съобщение на дейтаграма към получаващата нишка, за да деблокира приемащата нишка след изтичане на периода на изчакване. Нишката на времето за изчакване е реализирана като свой собствен клас и получаващата нишка създава екземпляр на класа на времето за изчакване точно преди блокирането на метода за получаване. Следващият код показва изпълнението на класа на времето за изчакване. Имайте предвид, че за краткост обработката на изключения е пропусната.

импортиране на java.io. *; импортиране на java.net. *; импортиране на java.lang. *; публичният клас DatagramWatchdogTimer реализира Runnable {DatagramWatchdogTimer (int timeoutSeconds) хвърля SocketException {timeout = timeoutSeconds; socket = нов DatagramSocket (); datagramPort = socket.getLocalPort (); Тема thisThread = нова нишка (тази); thisThread.start (); } public int getPort () {return datagramPort; } public void run () {// създаване на стандартно съобщение за отговор, което показва // съобщението е дошло от DatagramWatchdogTimer // в моя случай е достатъчна нула. String replyStr = ново цяло число (0) .toString (); байт [] replyBuf = нов байт [replyStr.length ()]; replyStr.getBytes (0, replyStr.length (), replyBuff, 0); int replyLength = replyStr.length (); // получаване на съобщение от приемащата нишка. // това е необходимо, за да знаем как да изпратим съобщението за деблокиране // обратно към него.байт [] буфер = нов бут [128]; DatagramPacket пакет = нов DatagramPacket (буфер, буфер.дължина); socket.receive (пакет); // изчакайте времето за изчакване за секунди и след това изпратете обратно деблокиращо // съобщение. Thread.sleep (изчакване * 1000); int requeststorPort = packet.getPort (); InetAddress requeststorAddress = packet.getAddress (); DatagramPacket sendPacket = нов DatagramPacket (replyBuff, replyLength, requeststorAddress, requeststorPort); DatagramSocket sendSocket = нов DatagramSocket (); sendSocket.send (sendPacket); } частен int таймаут; private int datagramPort; частен DatagramSocket сокет; }getPort (); InetAddress requeststorAddress = packet.getAddress (); DatagramPacket sendPacket = нов DatagramPacket (replyBuff, replyLength, requeststorAddress, requeststorPort); DatagramSocket sendSocket = нов DatagramSocket (); sendSocket.send (sendPacket); } частен int таймаут; private int datagramPort; частен DatagramSocket сокет; }getPort (); InetAddress requeststorAddress = packet.getAddress (); DatagramPacket sendPacket = нов DatagramPacket (replyBuff, replyLength, requeststorAddress, requeststorPort); DatagramSocket sendSocket = нов DatagramSocket (); sendSocket.send (sendPacket); } частен int таймаут; private int datagramPort; частен DatagramSocket сокет; }

Както бе споменато по-горе, когато вашето приложение трябва да получи съобщение на дейтаграма, то може да създаде екземпляр на DatagramWatchdogTimerкласа, за да зададе период на изчакване. Ако приложението не получи реално съобщение в рамките на секунди за изчакване, то ще се отблокира, като получи съобщение за деблокиране от DatagramWatchdogTimerкласа.

Ето пример:

// код на приложение int timeoutSeconds = 5; InetAddress myAddress = InetAddress.getByName (""); // създаване на екземпляр на класа на таймера DatagramWatchdogTimer wdTimer = нов DatagramWatchdogTimer (timeoutSeconds); int wdPort = wdTimer.getPort (); // изпратете съобщение до wdTimer, за да стартирате таймера // msgBuff може да бъде каквото искате. String msgString = new String ("time me"); байт [] msgBuff = нов байт [msgString.length ()]; msgString.getBytes (0, msgString.length (), msgBuff, 0); DatagramSocket сокет = нов DatagramSocket (); DatagramPacket wdPacket = нов DatagramPacket (msgBuff, msgLength, myAddress, wdPort); socket.send (wdPacket); // сега можете да четете от сокета и да имате някои уверения //, че ще блокирате само за timeoutSeconds. байт [] буфер = нов байт [1024]; DatagramPacket пакет = нов DatagramPacket (буфер,буфер.дължина); socket.receive (пакет); if (myAddress.equals (packet.getAddress) == true) {// получено съобщение от обекта на таймера} else {// получено реално съобщение}

Когато използвате тази техника, не забравяйте да използвате един и същ DatagramSocket както за изпращане към обекта DatagramWatchdogTimer, така и за получаване на дейтаграми. Това гарантира, че обектът DatagramWatchdogTimer знае къде да изпрати съобщението за деблокиране. Също така, в примерния код, показан по-горе, е използван динамично разпределен порт чрез инстанциране на DatagramSocket () без никакви аргументи. Той би работил и с помощта на добре познат порт по ваш избор, като DatagramSocket (8000). И накрая, може да искате обектът таймер да изпрати повече от едно съобщение за деблокиране - само за да увеличи шансовете за получаване от приложението. Това не би трябвало да представлява проблем, тъй като обектът таймер се изпълнява като нишка на същата машина като приложението.

Алберт Лопес е бил член на техническия персонал на Sun Microsystems от 1989 до 1995 г. Наскоро се е присъединил към персонала на Информационните системи към Чикагския съвет по търговия, където е водещ член на екипа за разработка на Java, който разработва следващото поколение електронна система за търговия, използваща Java.

Тази история, "Java Съвет 18: Внедряване на функция за изчакване за JDK 1.0.2 DatagramSocket" първоначално е публикувана от JavaWorld.