Um guia para UDP em Java
1. Visão geral
Neste artigo, exploraremos a comunicação em rede com Java, por meio do User Datagram Protocol (UDP).
UDP é um protocolo de comunicação quetransmits independent packets over the network with no guarantee of arrival and no guarantee of the order of delivery.
A maioria das comunicações pela Internet ocorre através do TCP (Transmission Control Protocol), no entanto, o UDP tem seu lugar que exploraremos na próxima seção.
2. Por que usar UDP?
O UDP é bem diferente do TCP mais comum. Mas antes de considerar as desvantagens de nível superficial do UDP, é importante entender que a falta de sobrecarga pode torná-lo significativamente mais rápido do que o TCP.
Além da velocidade, também precisamos lembrar que alguns tipos de comunicação não exigem a confiabilidade do TCP, mas valorizam a baixa latência. O vídeo é um bom exemplo de aplicativo que pode se beneficiar da execução de UDP em vez de TCP.
3. Criação de aplicativos UDP
A construção de aplicativos UDP é muito semelhante à construção de um sistema TCP; a única diferença é que não estabelecemos uma conexão ponto a ponto entre um cliente e um servidor.
A configuração também é muito simples. Java é fornecido com suporte de rede integrado para UDP - que faz parte do pacotejava.net. Portanto, para realizar operações de rede sobre UDP, precisamos apenas importar as classes do pacotejava.net:java.net.DatagramSocketejava.net.DatagramPacket.
Nas seções a seguir, aprenderemos como projetar aplicativos que se comunicam por UDP; vamos usar o protocolo de eco popular para este aplicativo.
Primeiro, criaremos um servidor de eco que enviará de volta qualquer mensagem enviada a ele, depois um cliente de eco que enviará qualquer mensagem arbitrária ao servidor e, finalmente, testaremos o aplicativo para garantir que tudo esteja funcionando bem.
4. O servidor
Na comunicação UDP, uma única mensagem é encapsulada emDatagramPacket, que é enviada por meio deDatagramSocket.
Vamos começar configurando um servidor simples:
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();
}
}
Criamos umDatagramSocket global que usaremos para enviar pacotes, um array de bytes para embrulhar nossas mensagens e uma variável de status chamadarunning.
Para simplificar, o servidor está estendendoThread, para que possamos implementar tudo dentro do métodorun.
Dentro derun, criamos um loop while que só executa até querunning seja alterado para falso por algum erro ou uma mensagem de encerramento do cliente.
No topo do loop, instanciamos aDatagramPacket para receber mensagens de entrada.
Em seguida, chamamos o métodoreceive no soquete. Este método bloqueia até que uma mensagem chegue e a armazena dentro da matriz de bytes deDatagramPacket passada para ele.
Depois de receber a mensagem, recuperamos o endereço e a porta do cliente, pois enviaremos a resposta de volta.
A seguir, criamos umDatagramPacket para enviar uma mensagem ao cliente. Observe a diferença de assinatura com o pacote de recebimento. Este também requer endereço e porta do cliente para o qual estamos enviando a mensagem.
5. O cliente
Agora vamos lançar um cliente simples para este novo servidor:
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();
}
}
O código não é tão diferente do servidor. Temos nossoDatagramSockete global e endereço do servidor. Nós os instanciamos dentro do construtor.
Temos um método separado que envia mensagens para o servidor e retorna a resposta.
Primeiro, convertemos a mensagem de string em uma matriz de bytes e, em seguida, criamos umDatagramPacket para enviar mensagens.
Em seguida - enviamos a mensagem. Imediatamente convertemosDatagramPacket em um receptor.
Quando o eco chega, convertemos os bytes em uma string e retornamos a string.
6. O teste
Em uma classeUDPTest.java, simplesmente criamos um teste para verificar a capacidade de eco de nossos dois aplicativos:
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();
}
}
Emsetup, iniciamos o servidor e também criamos o cliente. Já no métodotearDown, enviamos uma mensagem de encerramento ao servidor para que ele feche e ao mesmo tempo fechamos o cliente.
7. Conclusão
Neste artigo, aprendemos sobre o User Datagram Protocol e construímos com êxito nossos próprios aplicativos cliente-servidor que se comunicam por UDP.
Para obter o código-fonte completo dos exemplos usados neste artigo, você pode verificar oGitHub project.