Diferencia entre revisiones de «Programación de comunicacións en rede con Java»

De MediaWiki
Ir a la navegación Ir a la búsqueda
Línea 443: Línea 443:
 
= Creditos e referencias=
 
= Creditos e referencias=
 
* [https://www.sintesis.com/desarrollo%20de%20aplicaciones%20multiplataforma-341/programaci%C3%B3n%20de%20servicios%20y%20procesos-ebook-2910.html Programación de servicios y procesos. Carlos Alberto Cortijo Bon ISBN: 9788413571041]
 
* [https://www.sintesis.com/desarrollo%20de%20aplicaciones%20multiplataforma-341/programaci%C3%B3n%20de%20servicios%20y%20procesos-ebook-2910.html Programación de servicios y procesos. Carlos Alberto Cortijo Bon ISBN: 9788413571041]
 +
 +
== Sockets ==
 
* [https://docs.oracle.com/javase/tutorial/networking/sockets/readingWriting.html Reading from and Writing to a Socket]
 
* [https://docs.oracle.com/javase/tutorial/networking/sockets/readingWriting.html Reading from and Writing to a Socket]
 
* [https://www.cs.uic.edu/~troy/spring05/cs450/sockets/socket.html Socket Examples]
 
* [https://www.cs.uic.edu/~troy/spring05/cs450/sockets/socket.html Socket Examples]
 +
 +
=== Exemplo de xogo de adiviñar números ===
 +
* [https://programmerclick.com/article/5830172001/ Ejemplo de juego de números de adivinanzas de operaciones de sockets multiproceso]
 +
* [http://ayudavariables.blogspot.com/2013/08/secreto.html?m=1 Ejemplo Cliente/Servidor número secreto]
 +
* [https://github.com/RNogales94/Practicas-Redes/blob/master/P2%20-%20Cliente%20:%20Servidor/Ejercicio%205/src/fr/practica2/pkg5/ClienteAdivinador.java Otro Cliente/Servidor número secreto]

Revisión del 09:46 24 sep 2021

Comunicaciones en rede

O paquete java.net proporciona clases que permiten levar a cabo comunicaciíns entre procesos utilizando os protocolos estándares da familia de TCP/IP. Pode dividirse en dúas seccións:

  1. Clases de baixo nivel que permiten representar as principales entidades dos niveles de enlace, rede e transporte;
  2. Clases de alto nivel relacionadas con protocolos de nivel de aplicación

Comezaremos revisando as clases para interfaces de rede e enderezos IP, para despois progresar en algocentral nas comunicacións en rede: a programación de sockets de UDP e de TCP, cos que se desenvolverán programas servidores e clientes que se comunican utilizando os devanditos protocolos de transporte UDP e TCP; e que se pode considerar que implementan sencillos protocolos de nivel de aplicación.

Clases de baixo nivel do paquete java.net
Interfaces de rede NetworkInterface: interfaz de rede
Enderezos IP InetAddress: enderezo IP
Inet4Address: enderezo IPv
Inet6Address: enderezo IPv6
InterfaceAddress:enderezo IP máis información relativa á rede á que pertenece a interfaz
Sockets Socket: socket TCP de cliente, para conectar cun proceso servidor mediante TCP
ServerSocket: socket TCP de servidor, que acepta conexións desde un socket de cliente mediante TCP.
DatagramSocket: socket de UDP, que se usa para enviar e recibir datagramas de UDP

Interfaces de rede

As interfaces de red presentes no sistema podense amosar cos comandos:

  • ifconfig ou ip en Linux
  • ipconfig en Windows.

A clase NetworkInterface ten métodos estáticos que permiten obter unha enumeración de todas as interfaces de rede ou NetworkInterface existentes no sistema.

Una NetworkInterface pode ter máis dunha configuración IP asociada,e normalmente cando menos unha para IPv4 e outra para IPv6. Con distintos métodos da clase podense obter para cada unha obxectos de tipo InterfaceAddress e InetAddress.

A clase InterfaceAddress proporciona información adicional a InetAddress coma por exemplo a lonxitude da máscara de rede ou o enderezo de broadcast da rede á que pertence (para un enderezo IPv4).

Na táboa explicanse alguns dos métodos de NetworkInterface.

Métodos da clase NetworkInterface
Método Funcionalidade
static Enumeration<NetworkInterface> getNetworkInterfaces() Devolve todas as interfaces de rede existentes na máquina.
A partir do Enumeration pódese obter un Iterator para iterar sobre elas.
String getDisplayName()
String getName()
Devuelven o nome da interfaz
byte[] getHardwareAddress() Devolve o enderezo MAC en forma de array de 6 bytes (48 bits).
Enumeration<InetAddress> getInetAddresses()
List<InterfaceAddress> getInterfaceAddresses()
Devolven os enderezos IP asociados á interfaz. Será en xeral cando menos un enderezo IPv4 e un IPv6.


Un obxecto InterfaceAddress proporciona máis información que InetAddress. Por exemplo:

  • a lonxitude da máscara de rede
  • o enderezo de broadcast para a redhe á que pertence a interfaz (para IPv4).
boolean isLoopback() Determina se unha interfaz é de tipo loopback.

O exemplo permitirache familiarizarte co entorno de rede no que está integrado o teu ordenador; o coñecemento poderá ser de utilidade para crear programas que se comuniquen con outros desenvoltos por outros compañeiros, utilizando os protocolos de transporte UDP e TCP.

Exemplo con programa que amosa información das interfaces de rede

Aquí está o código dun programa que amosa información de todas as interfaces de rede presentes no sistema.

Amosa información da súa configuración para IPv4 e IPv6 (enderezos IP, máscaras de rede, enderezos de broadcast, etc).

Cuestións. 
Antes de executar o programa asegúrate de que o equipo ten conexión a internet ou a unha rede local. 
¿En qué cambia a saída do programa cando se desconecta o cable de rede ou se desactiva a interfaz de rede desde o sistema operativo? 
¿Para qué tipos de interfaces se amosa información? 
¿Hay alguna que esté sempre activa? ¿Cal? ¿Por qué?

Enderezos IP

Unha interfaz de rede pode ter configurada un ou varios enderezos IPv4 e un ou varios enderezos IPv6; e cada un cos seus correspondentes máscaras de rede.

As clases que permiten xestionar esta información:

  • InterfaceAddress: Representa a configuración IP dunha interfaz. Esto inclúe o enderezo IP e parámetros adicionais:
    • Lonxitude da máscara de rede (número de bits que no enderezo IP especifican a rede)
    • Cando se trata dun enderezo IPv4, enderezo de broadcast para a rede á que pertence a interfaz
  • InetAddress: Representa un enderezo IP. Ten dúas subclases para representar enderezos IPv4 e IPv6:
    • Inet4Address
    • Inet6Address

A clase InterfaceAddresss es muy sencilla y sus principales métodos se muestran en el cuadro 3.6. Para entender mejor su funcionamiento, hay que tener en cuenta que representa la conguración para IP de una interfaz de red. Por lo tanto, puede corresponder a cualquiera de las versiones de este protocolo, IPv4 o IPv6. Tiene un método para obtener la dirección IP y métodos adicionales para obtener otros parámetros de la conguración.

Métodos da clase InterfaceAddress
Método Funcionalidade
InetAddress getAddress() Devolve o enderezo IP.
short getNetworkPrefixLength() Devolve a lonxitude da máscara de rede (o número de bits dentro do enderezo IP que especifican a rede
InetAddress getBroadcast() Devoelve o enderezo de broadcast para a rede á que pertence o enderezo IP (so no caso de que se trate dun enderezo de IPv4; con enderezo de IPv6 devolve null

A clase InetAddress ten toda a funcionalidade precisa para realizar calquer tipo de operación sen preocuparse de se o enderezo IP é de IPv4 o IPv6; porén na práctica non adoitan utilizarseas súas subclases Inet4Address e Inet6Address.

A táboa amosa algúns métodos desta clase. Ten ademáis algúns métodos estáticos para resolución de nombres que se verán ne seguinte sección

Métodos da clase InetAddress
Método Funcionalidade
static InetAddress getByName(String host) Obten unha InetAddress para o host. En host pódese proporcionar un enderezo IP (analízase e valçidase o enderezo IP e obtense un obxecto de clase Inet4Address ou Inet6Address) ou un nome de host (utilizarase o mecanismo de resolución de nomes para obter un enderezo IP)
String getHostAddress() Devolve a representación textual do enderezo IP
byte[] getAddress() Devolve un array cos bytes que compoñen o enderezo IP (4 con IPv4 e 16 con IPv6)
static InetAddress getByAddress(byte[] addr) Devolve unha InetAddress para o enderezo IP dado, especificado como un array de bytes
boolean isReachable(int timeout) Determina se o enderezo é alcanzable, especificando un tempo máximo de espera (timeout) en milisegundos
boolean isSiteLocalAddress() Determina se é enderezo é local ou privado. Os rangos de enderezos para redes privadas especifícanse na RFC 1918. As redes privadas de clase C para IPv4 (as máis frecuentes) son 192.168.X.0/24, con 0 <= X <= 255
boolean isLoopbackAddress() Determina se o enderezo IP é dunha interfaz de tipo loopback
static InetAddress getLoopbackAddress() Devolve o enderezo de loopback:
  • 127.0.0.1 para IPv4 (en realidade segundo os estándares de internet é calquera da forma 127/8; isto é, cos 8 primeiros bits formando o valor 127, coa forma 127.*.*.*)
  •  ::1 para IPv6

Resolución de nomes

A clase InetAddress ten métodos estáticos:

  • que realizan resolución de nomes: dado un nome, permiten obtener o enderezo IP asociado.
  • que realizan resolución inversa de nomes: permiten obter un nome de host a partir do seu enderezo IP.
Métodos da clase InetAddress relacionados con resolución denomes
Método Funcionalidade
static InetAddress getByName(String host) Obten un enderezo IP a partir dun nome de host, utilizando servizos de resolución de nomes ou ben a partir dunha representación textual dun enderezo IP
static InetAddress[] getAllByName(String host) Similar o método anterior pero máis completo; devolve un array con todos os enderezos IP que se pueden obter utilizando servizos de resolución de nomes; tamén se pode especificar o host mediante a representación textual dun enderezo IPv4 ou IPv6
public String getHostName() Este método permite realizar unha resolución inversa de nome: obter un nome de host a partir do seu enderezo IP. Se a InetAddress creouse sen especificar un nome para o host, enton realízase unha resolución inversa de nomes para obter o nome do host a partir do seu enderezo IP.
static InetAddress getByAddress (String host, byte[] addr) Crea unha InetAddress indicando un enderezo IP e un nome de host. Devolve o nome proporcionado ó crear a InetAddress sen realizar resolución inversa de nomes
String getCanonicalHostName() Devuelve o nome de host canónico ou FQDN (fully qualified domain name) utilizando o protocolo DNS para obter esta información.
static InetAddress getLocalHost() Devolve o enderezo IP do propio host. En Linux normalmente obtense o seu nome de /etc/hostname , e resolvese o nome para obter un enderezo IP. Dependendo do sistema poderíase obter o enderezo da interfaz de loopback, un enderezo IP privado pertencente á rede local, ou incluso unha IP externa ou pública. Se non se pode resolver este nombre, lánzase unha excepción de tipo UnknownHostException
Tarefa
Crea un programa que amose o nome e enderezo IP do propio host utilizando o método getLocalHost.

Sockets UDP

Introdución ó protocolo UDP

O protocolo de transporte UDP non é orientado a conexión. So permite o envío de paquetes de datos individuales chamados datagramas. Estos poden chegar en orde distinto a orden en que se enviaron, e incluso non chegar. Neste sentido, o protocolo de transporte UDP non aporta ningún valor engadido ó servizo de envío de datagramas IP proporcionado polo nivel de rede (ou de internet).

Un datagrama de UDP está encapsulado nun datagrama de IP, como se amosa na figura. Cada liña amosa 4 bytes. Arriba amosanse nunha regra os bits do 0 ó 31.


Campos do datagrama UDP
Porto orixe Porto destino
Lonxitude da mensaxe Checksum


Bits 0 - 15 16 - 31
0 Porto orixen Porto destino
32 Lonxitude da mensaxe Suma de verificación
64  
Datos
 

A cabecera UDP consta de 4 campos dos cales 2 son opcionais (con fondo vermello na táboa). Os campos dos portos orixen e destino son campos de 16 bits que identifican o proceso de emisión e recepción. Xa que UDP carece dun servidor de estado e a orixe UDP non solicita respostas, o puerto orixen é opcional; en caso de non ser utilizado, o porto orixen debe ser posto a cero.

Pódese ver que o conxunto dun datagrama de UDP encapsulado nun datagrama de IP conten, ademáis dos datos que se envían do proceso de orixe ó de destino, o enderezo IP e o porto de orixe e o enderezo IP e porto de destino; toda a información necesaria para que os datos cheguen o seu destino e toda a información necesaria para que o proceso que o recibe poida enviar datagramas como resposta ó proceso de orixe. A comunicación entre dous procesos mediante o protocolo UDP é moi similar á comunicación entre dúas personas por correo (postal ou electrónico): xunto coa mensaxe e os datos para que chegue o seu destino, están os datos para enviar unha resposta.

A API de Java permite enviar e recibir datagramas mediante UDP en forma de obxectos da clase DatagramPacket. Este clase ten métodos setter e getter para toda esta información. Amosanse a continuación os métodos getter:

Métodos getter da clase DatagramPacket
Método Funcionalidade
byte[] getData()
int getLength()
Obteñen os datos que conten o datagrama coma un array de bytes, e a lonxitude do array.
InetAddress GetAddress()
int getPort()
Obteñen enderezos IP e porto desde onde se enviou o datagrama. Poderían non estar informados.
Un datagrama no que no están informados sería análogo a unha carta anónima, sen remitente.

Na figura amósase cómo se pode utilizar a clase DatagramSocket para enviar e recibir datagramas de UDP entre dos procesos.

UDP é un protocolo sinxelo que pode ser apropiado para o intercambio de pequenas cantidades de información, ou cando é preferible rápidez na transmisión aínda que se poida perder algún paquete (coma no caso do streaming); nese caso ten coma vantaxes a súa sinxelez e rapidez.

Por estas características é utilizado por protocolos de nivel de aplicación tales como DNS ( aínda que os servidores de DNS tamén utilizan TCP para determinadas operacións que requiren a transferencia de cantidades maiores de información entre eles), SNMP ou DHCP.

Hai que ten moi en conta as limitacións de UDP e utilizaro só para aplicacións para as que sea axeitado.

A clase DatagramSocket

Un socket de UDP é a combinación dun enderezo IP máis un número de porto. Un proceso servidor que presta un servizo utilizando UDP crea un socket de UDP ligado a un porto e a unha interfaz de rede local, identificada polo seu enderezo. Entón, pode recibir datagramas enviados por procesos clientes. Se cuando se crea un socket non se especifica un enderezo IP, entonces pode recibir datagramas a través de calquera interfaz de rede local: dise que se ligou o socket a unha wildcard address.

A clase DatagramPacket utilízase para representar datagramas de UDP. Pódense enviar e recibir DatagramPacket a través dun DatagramSocket.

UDP permite ademáis de enviar e recibir datagramas de enderezos particulares (comunicación unicast):

  • Envío broadcast. Si se especica la dirección de broadcast de la red local, todos los hosts de la red local reciben el datagrama. Esto es muy sencillo y puede tener su utilidad. Más adelante, se propondrá algún ejercicio en que se saque partido de esto.
  • Comunicación multicast. Es posible utilizando la clase MulticastSocket . Un grupo de multicast está identicado por una dirección IP de clase D. Se puede crear un MulticastSocket ligado a un puerto local y luego unirlo al grupo especicando su dirección IP. No se verá más acerca de multicast con UDP aquí.

Os cadros amosan algúns dos métodos das clases DatagramSocket e DatagramPacket. Casi todas as operacións realizadas cun DatagramSocket poden provocar excepcións de tipo IOException . Esta clase implementa a interfaz Closeable polo que se pode utilizar nun bloque try … catch con recursos.

Métodos da clase DatagramSocket
Método Funcionalidade
DatagramSocket()
DatagramSocket(int port)
DatagramSocket(int port, InetAddress laddr)
Diversos constructores para un DatagramSocket para envío e recepción de datagramas de UDP.

O porto e o enderezo IP especificados son locales. O enderezo IP e o porto de destino para datagramas enviados van especificados no propio datagrama. Se se especifica o enderezo IP dunha interfaz activa, o socket lígase a ela. Se non, lígase a todas as interfaces activas (wildcard address). Pódese especificar un porto para enviar e recibir datagramas por él. Un proceso servidor normalmente fará iso. Un programa cliente normalmente non especificará un porto, e entón o sistema elixirá un porto efímero

void receive(DatagramPacket p) Recibe un datagrama desde a interfaz (especificada por un enderezo IP) e o porto o que está ligado o socket. Se non está ligado a ningunha interfaz específica pode recibir o datagrama por calquera interfaz. O enderezo IP e o puerto de orixen virán indicados no propio datagrama recibido
void send(DatagramPacket p) Envía un datagrama. O enderezo IP e o porto deben estar especificados no propio datagrama
setSoTimeout(int timeout) Establece un tempo máximo de espera cando se recibe un datagrama co método receive. Se pasado ese tempo non se recibíu un datagrama xenerarase unha excepción de tipo SocketTimeoutException. Un valor 0 para timeout significa espera indefinida, a funcionalidade por defecto de receive()
void close() Pecha o socket
void connect (InetAddress address, int puerto)
void connect (SocketAddress addr)
Conecta o socket a un enderezo e porto remotos de xeito que só se poden enviar datagramas a ese enderezo e porto ou recibilos dese enderezo e porto.

O nombre deste método non debe inducir a confusión. Que exista un método connect non é contradictorio co feito de que UDP sexa un protocolo non orientado a conexión, a diferencia de TCP

void disconnect{} Desconecta o socket
Métodos da clase DatagramPacket
Método Funcionalidade
DatagramPacket(byte[] buf, int length)
DatagramPacket(byte[] buf, int offset, int length)
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
Diversos constructores. Os parámetros corresponden a:
  • Secuencia de bytes que enviar no datagrama. Esta está no array de bytes buff. Hai que enviar un número de bytes dado por length
  • Enderezo IP e porto de destino, dados por address e port . Podense asignar tamén con setAddress(InetAddress iaddr) e setSocketAddress(SocketAddress address)
getAddress(), setAddress()

getData(), setData()
getLength(),setLength()
getOffset(),setOffset()
getPort(),setPort()
getSocketAddress(),setSocketAddress()

Diversos métodos getter e setter.

Programación de aplicacións servidores e clientes baseadas en UDP

Os programas de exemplo virán en parellas: un programa servidor e un programa cliente. Os enderezos e portos que utilizar se especificarán mediante un argumento de liña de comandos.

Texto entre procesos. Codificación

Moitos dos programas transmiten textos entre procesos; xeneralmente será texto codificado en UTF-8.

Importante. Codificaciones de texto e codificación en UTF-8.
Na comunicación entre procesos é preciso facelo de acordo a un protocolo preestablecido de xeito que ambos poidan interpretar correctamente a información recibida desde o outro e así dar a resposta axeitada en cada caso; porén debemos asegurar que ambos utilizan o mesmo formato para os datos que se transmiten entre eles. 
No caso dun texto o proceso emisor debe utilizar sempre a mesma codificación, e o receptor debe interpretalo seempre conforme a esa mesma codificación. Se ambos procesos se executan en sistemas distintos poderían non usar a mesma codificación (que normalmente será UTF-8) para codificar o texto en orixen e para decodificarlo en destino; por iso non se pode asumir que será sempre UTF-8.
Nas aplicaciones típicas co protocolo UDP, a codificación de texto interven cuando se obten unha secuencia de bytes a partir dunha cadena de caracteres ou viceversa. Conven utilizar a codificación UTF-8. Para iso hai que facer o seguiente: 
  1. Obter a secuencia de bytes para un String s con s.getBytes("UTF-8") .
  2. Crear un String a partir de un byte[] b con new String(b, "UTF8") se todos os datos no array de bytes b son datos válidos. Nembargantes con UDP os datos dun DatagramPacket dg están en dg.getData(), e o número de bytes de datos válidos está en dg.getLength(). Por iso é preciso indicar o número de bytes para crear o String; e se pode crear con new String(dg.getData(), 0, dg.getLength(), "UTF-8") .

Exemplo. Echo de servidor e cliente

No seguiente exemplo o cliente envía unha cadena de caracteres ó servidor e este envía como resposta ó cliente a mesma liña pero antepoñendo un carácter #.

Tanto en cliente coma servidor seguense as pautas para obter un array de byte coa codificación en UTF-8 dun String; e inversamente para crear un String a partir da súa codificación en UTF-8 dada en un array de byte.closeable .

O porto para o que se crea o DatagramSocket pásase o programa servidor por liña de comandos. Pásaselle ó programa cliente ademáis o host servidor (por exemplo "localhost" se ambos se executan na mesma máquina.

Unha vez creado o DatagramSocket, úsase para recibir un datagrama (DatagramPacket) do proceso cliente co método receive. Para recibir os datos, débese crear un array de tipo byte[] datosRecibidos o suficiente grande como para recibir todos os datos que vaia a enviar o proceso cliente. Do datagrama recibido obtense o enderezo IP e o porto de procedencia do datagrama. Con eles crease un DatagramPacket de resposta que se envía polo mesmo DatagramSocket co método send.

Comezamos co código do servidor:

 1 package udp_echoserver;
 2 import java.io.IOException;
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 import java.net.InetAddress;
 6 import java.net.SocketException;
 7 public class UDP_EchoServer {
 8   private final static int MAX_BYTES = 1400;
 9   private final static String COD_TEXTO = “UTF-8”;
10   public static void main(String[] args) {
11     if (args.length < 1) {
12       System.err.println(“ERROR, indicar: puerto.”);
13       System.exit(1);
14     }
15     int numPuerto = Integer.parseInt(args[0]);
16     try(DatagramSocket serverSocket=new DatagramSocket(numPuerto)) {
17       System.out.printf(“Creado socket de datagramas para puerto %s.\n”, 
18         numPuerto);
19       while (true) {
20         System.out.println(“Esperando datagramas.”);
21         byte[] datosRecibidos = new byte[MAX_BYTES];
22         DatagramPacket paqueteRecibido = new DatagramPacket(
23           datosRecibidos,datosRecibidos.length);
24         serverSocket.receive(paqueteRecibido);
25         String lineaRecibida = new String(paqueteRecibido.getData(),
26             0, paqueteRecibido.getLength(), COD_TEXTO);
27         InetAddress IPCliente = paqueteRecibido.getAddress();
28         int puertoCliente = paqueteRecibido.getPort();
29         System.out.printf(“Recibido datagrama de %s:%d (%s)\n”,
30           IPCliente.getHostAddress(), puertoCliente, lineaRecibida);
31         String respuesta = “#” + lineaRecibida + “#”;
32         byte[] b = respuesta.getBytes(COD_TEXTO);
33         DatagramPacket paqueteEnviado = new DatagramPacket(
34           b,  b.length, IPCliente, puertoCliente);
35         serverSocket.send(paqueteEnviado);
36       }
37     } catch (SocketException ex) {
38       System.out.println(“Excepción de sockets”);
39       ex.printStackTrace();
40     } catch (IOException ex) {
41       System.out.println(“Excepción de E/S”);
42       ex.printStackTrace();
43     }
44   }
45 }

O programa cliente crea un DatagramSocket, mais non ligado a un porto como o facía o programa servidor. Le liña tras liña de entrada estándar, obtén a súa codificación en UTF-8, e a envía ó programa servidor. Despois agarda a recibir unha resposta: de non ser por clientSocket.connect(IPServidor, numPuerto), a chamada posterior a client-Socket.receive(paqueteRecibido) podería obter un datagrama enviado desde calquer outro enderezo IP ou porto. Porén é recomendable utilizar este método por precaución, a non ser que se desexe que o programa poida recibir datagramas desde máis dunha posible combinación de enderezo IP e porto.

 1 package udp_echoclient;
 2 import java.io.BufferedReader;
 3 import java.io.IOException;
 4 import java.io.InputStreamReader;
 5 import java.net.DatagramPacket;
 6 import java.net.DatagramSocket;
 7 import java.net.InetAddress;
 8 import java.net.SocketException;
 9 public class UDP_EchoClient {
10   private final static int MAX_BYTES = 1400;
11   private final static String COD_TEXTO =”UTF-8”;
12   public static void main(String[] args) {
13     if (args.length < 2) {
14       System.err.println(“ERROR, indicar: host_servidor puerto”);
15       System.exit(1);
16     }
17     String nomHost = args[0];
18     int numPuerto = Integer.parseInt(args[1]);
19     try (DatagramSocket clientSocket = new DatagramSocket();
20       InputStreamReader isrStdIn = new InputStreamReader(System.in,
21         COD_TEXTO);
22       BueredReader brStdIn = new BueredReader(isrStdIn)) {
23       String lineaLeida;
24       System.out.println(“Introducir líneas. Línea vacía para terminar.”);
25       System.out.print(“Línea>”);
26       while ((lineaLeida = brStdIn.readLine()) != null
27               && lineaLeida.length() > 0) {
28         InetAddress IPServidor = InetAddress.getByName(nomHost);
29         byte[] b = lineaLeida.getBytes(COD_TEXTO); 
30         DatagramPacket paqueteEnviado = new DatagramPacket(
31           b, b.length, IPServidor, numPuerto);
32         clientSocket.connect(IPServidor, numPuerto);
33         clientSocket.send(paqueteEnviado);
34         byte[] datosRecibidos = new byte[MAX_BYTES];
35         DatagramPacket paqueteRecibido =  new DatagramPacket(
36           datosRecibidos, datosRecibidos.length);
37         clientSocket.receive(paqueteRecibido);
38         String respuesta = new String(paqueteRecibido.getData(),
39           0, paqueteRecibido.getLength(), COD_TEXTO);
40        System.out.printf(“Datagrama recibido de %s:%d: %s\n”,
41           paqueteRecibido.getAddress().getHostAddress(),
42           paqueteRecibido.getPort(), respuesta);
43         System.out.print(“Línea>”);
44       }
45     } catch (SocketException ex) {
46       System.out.println(“Excepción de sockets”);
47       ex.printStackTrace();
48     } catch (IOException ex) {
49       System.out.println(“Excepción de E/S”);
50       ex.printStackTrace();
51     }
52   }
53 }

Probar funcionamento do servidor sen necesidade do cliente

Co comando nc podense enviar datagramas de UDP cun texto, e amosar o texto contido no datagrama de resposta recibido. Con iso podemos probar o funcionamiento dun programa servidor sen necesidade de crear un programa cliente. Se o servidor de eco anterior está funcionando no puerto 8000 do mesmo ordenador (localhost), se lle pode enviar un datagrama co texto "ola echo" e amosar a resposta con:

$ echo -n "ola eco" | nc -u localhost 8000
#ola eco#

Programación distribuída baseada en UDP

Programación de servidores multifío baseados en UDP

Sockets TCP

Programación de aplicacións servidores e clientes baseadas en TCP

Programación de servidores multifío baseados en TCP

Programación distribuída baseada en TCP

Creditos e referencias

Sockets

Exemplo de xogo de adiviñar números