Ръководство за UDP в Java

1. Общ преглед

В тази статия ще проучим мрежовата комуникация с Java по протокола за потребителски дейтаграми (UDP).

UDP е комуникационен протокол, който предава независими пакети по мрежата без гаранция за пристигане и гаранция за реда на доставка .

Повечето комуникации през интернет се осъществяват чрез протокола за контрол на предаването (TCP), но UDP има своето място, което ще проучим в следващия раздел.

2. Защо да използвам UDP?

UDP е доста различен от по-често срещания TCP. Но преди да разгледате недостатъците на UDP на повърхностно ниво, важно е да разберете, че липсата на режийни разходи може да го направи значително по-бърз от TCP.

Освен скоростта, ние също трябва да помним, че някои видове комуникация не изискват надеждността на TCP, но вместо това оценяват ниска латентност. Видеото е добър пример за приложение, което може да се възползва от работа над UDP вместо TCP.

3. Изграждане на UDP приложения

Изграждането на UDP приложения е много подобно на изграждането на TCP система; единствената разлика е, че не установяваме точка до точка връзка между клиент и сървър.

Настройката също е много ясна. Java се доставя с вградена мрежова поддръжка за UDP - която е част от пакета java.net . Ето защо, за да извършите мрежови операции над UDP, ние само трябва да импортирате класовете от java.net пакета: java.net.DatagramSocket и java.net.DatagramPacket .

В следващите раздели ще научим как да проектираме приложения, които комуникират през UDP; ще използваме популярния ехо протокол за това приложение.

Първо, ще изградим echo сървър, който изпраща обратно всяко съобщение, изпратено до него, след това echo клиент, който просто изпраща произволно съобщение до сървъра и накрая, ще тестваме приложението, за да сме сигурни, че всичко работи нормално.

4. Сървърът

В UDP комуникацията едно съобщение се капсулира в DatagramPacket, който се изпраща през DatagramSocket .

Нека започнем с настройка на прост сървър:

public class EchoServer extends Thread { private DatagramSocket socket; private boolean running; private byte[] buf = new byte[256]; public EchoServer() { socket = new DatagramSocket(4445); } public void run() { running = true; while (running) { DatagramPacket packet = new DatagramPacket(buf, buf.length); socket.receive(packet); InetAddress address = packet.getAddress(); int port = packet.getPort(); packet = new DatagramPacket(buf, buf.length, address, port); String received = new String(packet.getData(), 0, packet.getLength()); if (received.equals("end")) { running = false; continue; } socket.send(packet); } socket.close(); } }

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

За улеснение сървърът разширява Thread , за да можем да внедрим всичко вътре в метода run .

В рамките на изпълнението ние създаваме цикъл while, който просто се изпълнява, докато стартирането не бъде променено на false от някаква грешка или съобщение за прекратяване от клиента.

В горната част на цикъла създаваме екземпляр на DatagramPacket за получаване на входящи съобщения.

След това извикваме метода за получаване в сокета. Този метод блокира, докато не пристигне съобщение и съхранява съобщението в байтовия масив на DatagramPacket, предаден му.

След получаване на съобщението извличаме адреса и порта на клиента, тъй като ще изпратим отговора

обратно.

След това създаваме DatagramPacket за изпращане на съобщение до клиента. Забележете разликата в подписването с приемащия пакет. Това също изисква адрес и порт на клиента, на който изпращаме съобщението.

5. Клиентът

Сега нека пуснем прост клиент за този нов сървър:

public class EchoClient { private DatagramSocket socket; private InetAddress address; private byte[] buf; public EchoClient() { socket = new DatagramSocket(); address = InetAddress.getByName("localhost"); } public String sendEcho(String msg) { buf = msg.getBytes(); DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 4445); socket.send(packet); packet = new DatagramPacket(buf, buf.length); socket.receive(packet); String received = new String( packet.getData(), 0, packet.getLength()); return received; } public void close() { socket.close(); } }

Кодът не е толкова различен от сървърния. Разполагаме с глобалния DatagramSocket и адреса на сървъра. Инстанцираме ги в конструктора.

Имаме отделен метод, който изпраща съобщения до сървъра и връща отговора.

Първо преобразуваме низовото съобщение в байтов масив, след което създаваме DatagramPacket за изпращане на съобщения.

След това - изпращаме съобщението. Веднага преобразуваме DatagramPacket в получавателен.

Когато пристигне ехото, ние преобразуваме байтовете в низ и връщаме низа.

6. Тестът

В клас UDPTest.java просто създаваме един тест, за да проверим ехото на нашите две приложения:

public class UDPTest { EchoClient client; @Before public void setup(){ new EchoServer().start(); client = new EchoClient(); } @Test public void whenCanSendAndReceivePacket_thenCorrect() { String echo = client.sendEcho("hello server"); assertEquals("hello server", echo); echo = client.sendEcho("server is working"); assertFalse(echo.equals("hello server")); } @After public void tearDown() { client.sendEcho("end"); client.close(); } }

При настройката стартираме сървъра и също така създаваме клиента. Докато сме в метода tearDown , ние изпращаме съобщение за прекратяване до сървъра, за да може той да се затвори и в същото време да затворим клиента.

7. Заключение

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

За да получите пълен изходен код за примерите, използвани в тази статия, можете да разгледате проекта GitHub.