2011-06-15 24 views
5

Estoy aprendiendo redes de un libro java, así que soy un poco novato. No pude encontrar este problema en el libro o en línea, así que decidí preguntar en Internet.(java) ObjectInputStream deserialización de la versión incorrecta del objeto

El libro dice que use ObjectOutputStream y ObjectInputStream para enviar y recibir objetos a diferentes consolas.

Ahora, puedo recibir con éxito los objetos que envío, pero solo una vez. Cuando envío diferentes objetos: cadenas aleatorias, enteros e instancias sin nombre, la consola tiene todos los campos correctos. Pero cuando envío una instancia de un objeto, cambie el valor de uno de los campos de la instancia y vuelva a enviar el objeto, luego inpustream carga los valores de la instancia original.

Así que, por ejemplo, tengo una instancia de una clase con una int pública "var" igual a 1. Si envío la instancia de esta clase, el cliente la recibe e informa correctamente que var = 1. Sin embargo , si cambio var a 2 (en la misma instancia) y lo vuelvo a enviar, el cliente terminará llamando al método read() (¡así que debe haber recibido el nuevo objeto!), pero informará que var es 1. Si envíe la instancia a un cliente diferente que aún no haya recibido la instancia, informará correctamente var como 2 y continuará informándola como 2 incluso si cambio var.

El hecho de que el cliente lea la versión correcta de la instancia si no la ha recibido antes debe significar que el objeto se envía correctamente a través de la salida de salida; por alguna razón el inputstream simplemente no está funcionando. Es casi como si ve que es el mismo objeto, por lo que supone que tiene los mismos valores sin verificar. ¿Por qué sucede esto y cómo puedo solucionarlo?

Lo siento si estoy preguntando algo estúpido: el libro no explica cómo funcionan la serialización y los zócalos, simplemente cómo usarlos, por lo que podría estar muy confundido acerca de cómo usarlos. ¡Gracias!

código simple que escribí para probar el problema:

Servidor: (tiene una acción del temporizador para mantener el envío de objetos actualizados)

public void actionPerformed(ActionEvent e) 
{ 
    object.var++; 
      output.write(object); 
      output.flush(); 
      System.out.println(object.var); 
} 

cliente

public void run() 
{ 
    while(true) 
      { 
        Test t = (Test)input.readObject(); 
        System.out.println(t.var); 
      } 
    } 

Cuando estos programas se ejecutan la salida para la clase Servidor es 1,2,3,4 ... aumentando infinitamente, mientras que la salida del Cliente es solo 1,1,1,1,1,1,1, etc.

Gracias por tomarse el tiempo para leer esto. Lo siento si solo soy tonto, soy nuevo en esto.

EDITAR

: Lo sentimos, los read() era un mistype (i manualmente tecleé el código porque no podía EGET el formato correcto), me refería a input.readObject()

+0

Pregunta relacionada: http://stackoverflow.com/questions/15675262/. –

Respuesta

-1

Tantas horas que he gastado depurando un código como este. :)

No estoy seguro de cuál es la solución adecuada para esto, pero si crea una nueva instancia del objeto, o simplemente lo clona(), antes de enviarlo el código debería funcionar como se esperaba.

Parece que la máquina virtual reconoce el objeto que está recibiendo como uno que ya tiene, y simplemente actualiza el puntero en el cliente sin molestarse en comprobar realmente si hay algún cambio.

intenta ...

public void actionPerformed(ActionEvent e) 
{ 
    object.var++; 
    //assuming your object supports clone() 
    output.write(object.clone()); 
    output.flush(); 
    System.out.println(object.var); 
} 
+1

Una pequeña programación de culto a la carga nunca duele, ¿eh? –

+0

Después de bastantes horas de golpear su cabeza contra el escritorio tratando de descubrir por qué imprimir todos los campos en el servidor le da resultados diferentes que imprimir todos los campos en el lado del cliente, unirse al culto parece una gran idea. ;) – Mike

+4

'ObjectOutputStream.reset' es la solución adecuada :) –

3

¿Está utilizando read() o readObject() de ObjectInputStream? Si está utilizando read(), solo obtendrá un byte de datos. Intenta convertir el cliente

public void run() 
{ 
    while(true) 
    { 
    Test t = (Test)input.readObject(); 
    System.out.println(t.var); 
    } 
} 

EDIT: debería haber sido input.readObject();

+0

¿quisiste cambiar el código a' input.readObject() '? – Bohemian

+0

Sí ... gracias por ver mi supervisión. Voy a editar. – Suroot

+0

Gracias por esto. read() devolver un int es tan engañoso. Pone a prueba todas las comprobaciones de tipos de Java. – navjotk

12

El motivo es que ObjectOutputStream almacena en el caché las referencias de objeto y escribe referencias retrospectivas a la secuencia si el mismo objeto se escribe dos veces. Eso significa que cuando llamas al write la segunda vez que la transmisión no escribe una nueva copia del objeto, simplemente inserta una referencia al objeto que ya está escrito.

Puede evitar esto llamando al ObjectOutputStream.reset entre llamadas para escribir. Eso le dice a la transmisión que descarte cualquier referencia en caché.

Este comportamiento parece extraño, pero en realidad es necesario evitar bucles infinitos si intenta serializar un gráfico de objetos que tiene referencias circulares (es decir, escribir el objeto A que hace referencia al objeto B que a su vez hace referencia al objeto A).

+0

Esto funcionó! ¡Gracias! – superzipzop

+0

No se olvide de aceptar una respuesta :) Simplemente haga clic en la marca de verificación al lado de la respuesta que más le guste. –

+0

¡Acabas de resolver un problema en el que he estado trabajando durante horas! Muchas gracias! –

Cuestiones relacionadas