2010-10-22 29 views
10

Estoy tratando de enviar un objeto serializado de un proceso de servidor a un proceso de cliente en Java usando UDP. El problema es que el cliente está siendo bloqueado en el método de recepción. ¿Alguien puede ayudar?Enviar y recibir el objeto de serialización en UDP

aquí es el código de servidor para enviar el objeto:

ClientModel C1= new ClientModel(100,"Noor","Noor",38,38,"asd"); 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ObjectOutputStream oos = new ObjectOutputStream(baos); 
    oos.writeObject(C1); 
    oos.flush(); 
    byte[] Buf= baos.toByteArray(); 
    packet = new DatagramPacket(Buf, Buf.length, client, port); 
    socket.send(packet); 

y aquí está el código de cliente para la recepción del objeto:

byte[] buffer = new byte[100000]; 
packet = new DatagramPacket(buffer, buffer.length); 
socket.receive(packet); 
System.out.println("packet received"); 

sólo quiero recibir el objeto de poder reconstruir pero no puedo recibir el paquete en sí.

+0

quizás necesite vaciar el búfer ... – ultrajohn

Respuesta

13

I no sabe lo que quiere lograr en el final, pero trabajando con UDP no es tan fácil ... la razón principal está en la descripción del objeto DatagramPacket:

paquetes de datagramas se utilizan para implementar un servicio de entrega de paquetes sin conexión servicio. Cada mensaje se enruta desde una máquina a otra basándose únicamente en en la información contenida en ese paquete . Los paquetes múltiples enviados desde una máquina a otra pueden enrutarse de manera diferente, y pueden llegar en cualquier orden . La entrega del paquete no está garantizada .

Un buen tutorial cuando se trabaja con UDP es http://download.oracle.com/javase/tutorial/networking/datagrams/clientServer.html

Acerca de su bloqueo:

recibe un paquete de datagramas desde este conector . Cuando este método retorna, el buffer del DatagramPacket se rellena con los datos recibidos. El paquete de datagramas también contiene la dirección IP del remitente, y el número de puerto en la máquina del remitente.

Este método bloquea hasta que se reciba un datagrama . El campo de longitud del objeto de paquete de datagrama contiene la longitud del mensaje recibido. Si el mensaje es más largo que la longitud del paquete , el mensaje se trunca.

casi no lo pruebo, pero estoy bastante seguro de que - basándose en la descripción - que la función datagramsocket.reseive bloqueará hasta que se llena el paquete (en su caso hasta que se reciban 100000 bytes).

Le sugiero que comience con un datagrampacket con una longitud fija conocida, donde transmite el tamaño de la carga real.Algo así como:

public static void main(String[] args) { 
    ClientModel c1 = new ClientModel(); 
    c1.data = 123; 
    c1.name = "test"; 

    try { 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(baos); 
     oos.writeObject(c1); 
     oos.flush(); 
     // get the byte array of the object 
     byte[] Buf= baos.toByteArray(); 

     int number = Buf.length;; 
     byte[] data = new byte[4]; 

     // int -> byte[] 
     for (int i = 0; i < 4; ++i) { 
      int shift = i << 3; // i * 8 
      data[3-i] = (byte)((number & (0xff << shift)) >>> shift); 
     } 

     DatagramSocket socket = new DatagramSocket(1233); 
     InetAddress client = InetAddress.getByName("localhost"); 
     DatagramPacket packet = new DatagramPacket(data, 4, client, 1234); 
     socket.send(packet); 

     // now send the payload 
     packet = new DatagramPacket(Buf, Buf.length, client, 1234); 
     socket.send(packet); 

     System.out.println("DONE SENDING"); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 
} 

Por otro lado Ahora ya sabe sus tamaños:

public static void main(String[] args) { 
    try { 
     DatagramSocket socket = new DatagramSocket(1234); 

     byte[] data = new byte[4]; 
     DatagramPacket packet = new DatagramPacket(data, data.length); 
     socket.receive(packet); 

     int len = 0; 
     // byte[] -> int 
     for (int i = 0; i < 4; ++i) { 
      len |= (data[3-i] & 0xff) << (i << 3); 
     } 

     // now we know the length of the payload 
     byte[] buffer = new byte[len]; 
     packet = new DatagramPacket(buffer, buffer.length); 
     socket.receive(packet); 

     ByteArrayInputStream baos = new ByteArrayInputStream(buffer); 
     ObjectInputStream oos = new ObjectInputStream(baos); 
     ClientModel c1 = (ClientModel)oos.readObject(); 
     c1.print(); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 
} 

El clas CientModel sI utilizado:

public class ClientModel implements Serializable{ 
    private static final long serialVersionUID = -4507489610617393544L; 

    String name = ""; 
    int data = 1; 

    void print() { 
     System.out.println(data +": " + name); 
    } 
} 

He probado el código y funciona muy bien. Espero que ayude (obtuve el byte-to-int y alrededor de http://www.tutorials.de/java/228129-konvertierung-von-integer-byte-array.html)

Editar: Como se dice en los comentarios, a menudo es una muy mala idea usar UDP, principalmente, porque no sabes si tus paquetes se reciben en el orden correcto, o incluso en absoluto. UDP NO garantiza eso. No hice demasiada programación udp, pero la única parte en la que puede confiar (si lo entendí correctamente) es que si obtiene un paquete y encaja dentro del datagrama (65.527 bytes - vea https://en.wikipedia.org/wiki/User_Datagram_Protocol) contendrá la totalidad cosa. Entonces, si no le importa el orden en que aparece el mensaje y su objeto encaja en el datagrama, debería estar bien.

Edit2: En cuanto al código: no lo use como está. es solo un ejemplo, ind UDP solo debería tener un tipo de paquete, y esto con un tamaño conocido. de esa manera no necesitas enviar el "tamaño". Si usa el código como se muestra arriba, y se descarta un paquete, el siguiente paquete tendrá el tamaño incorrecto (es decir, si se descarta el primer paquete, de repente está verificando los primeros bytes de la carga útil para obtener el tamaño).

+0

No estoy probado tampoco, pero a partir de la descripción de C recvfrom (2), es evidente que la lectura de la conexión UDP puede volver tan pronto como se lea el datagrama completo y el número real de bytes leídos se devuelve (en el caso de JDK estará en el campo DatagramPacket.length). Sugiero escribir un cliente/servidor Java echo simple para probar el comportamiento. –

+0

Los datagramas pueden llegar desordenados o nunca llegar. Es posible que tenga que confirmar el paquete inicial para confirmar el siguiente tamaño esperado y luego anotar el paquete de carga – user12345613

+0

. ¿Entonces envía la longitud antes de enviar la carga real? ¿Cómo cambia esto la situación? La sintaxis en ambos extractos del código fuente para transmitir la carga útil sigue siendo la misma. Estoy confundido – iGbanam

1

me dio realmente probarlo, pero estoy bastante seguro de que - en base a la descripción - que la función datagramsocket.reseive bloqueará hasta que se llena el paquete (en su caso hasta 100000 bytes son recibidos ).

Esto está mal. La función de recepción se bloqueará hasta que se reciba un datagrama, que puede ser más pequeño que el tamaño del búfer (y generalmente lo será). El método packet.getLength() le dirá qué tan grande era.

Cuestiones relacionadas