Serialização

Pessoal, estou com um problemão aqui que não consigo resolver.

Fucei no GUJ sobre o assunto “serialização” e desta forma consegui fazer o que eu precisava: serializar objetos.

Ok! Só que agora tenho um problema: as vezes funciona e as vezes dá erro! Isso mesmo gente! Só as vezes e não consigo entender o que pode fazer o erro acontecer nesses casos! Já revirei todos os exemplos possíveis daqui do GUJ e não consigo encontrar qual possa ser o problema. Vou explicar a situação:

De um lado tenho um Server que recebe um pedido do Client, processa e pode dar a resposta de duas formas: ou um objeto String ou um objeto X que eu tenho aqui.
Meu objeto X é um objeto que tem apenas atributos de tipo String, cerca de 20 atributos, todos do tipo String.
Abaixo o código de onde faço a serialização desse objeto pra enviá-lo:

[code]Object obj = TrataPacote(alguns parâmetros); // retorna um Object que é ou uma String ou um X

ObjectOutputStream objOutputStream = new ObjectOutputStream(meuSocket.getOutputStream());
if (obj instanceof X)
objOutputStream.writeObject((X)obj);
else
objOutputStream.writeObject((String)obj);
objOutputStream.flush();
objOutputStream.close();[/code]

Do outro lado tenho o Client que enviou o pedido pro Server e agora está esperando a serialização desse Object como resposta.
Abaixo o código de onde recebo o objeto serializado:

try { ObjectInputStream objInputStream = new ObjectInputStream(meuSocket.getInputStream()); Object resposta = objInputStream.readObject(); //aqui objInputStream.close(); } catch (Exception e) { e.printStackTrace(); }

Bom, o Server e o Client estão rodando na mesma máquina, em duas janelas diferentes. Eu abro o Server primeiro, depois o Client. Se eu mantiver o Server aberto e for abrindo e fechando o Client pra testar, as vezes chega o objeto correto, as vezes não. Extremamente aleatório! Sempre que ocorrer do retorno ser String, funciona. Quando é o caso de retornar o objeto X (a maioria das vezes), ocorre esta situação aleatória que mencionei de as vezes chegar certo as vezes não.

Quando não dá certo ele entra no meu “catch” e imprime a Exception abaixo:

[color=red]java.io.StreamCorruptedException: illegal handle value
at java.io.ObjectInputStream.readHandle(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at minhaClasse:linha[/color]

A linha apontada pela Exception é a que está marcada com o //aqui no código do Client.

A sensação que tenho é de que “as vezes” o objeto chega corrompido, ou talvez o Client comece a ler antes do Server terminar de enviar, não sei, algo assim. Mas pq “as vezes”? Seria isso msm que estou suspeitando?! Como resolver?!?!?!

Por favor, alguma luz pessoal?!?!? :cry: :cry: :cry:

Se eu estiver falando besteira, pelo amor de deus algúem se pronuncie, mas acredito que essa sua suposição está correta. Tipo, acredito que quando você manda ler alguma coisa no inputStream do seu socket ele lê o que tiver lá naquele momento, mesmo não estando todos os bytes do objeto do “outro lado”, sacou?
Acho que uma solução para isso seria você mandar primeiro a quantidade total de bytes do objeto que você vai enviar, dessa forma você pode tratar o seu cliente e mandar ler do inputStream somente quando todos os bytes tiverem sido escritos.
Mas pensando nessa sugestão que te falei agora, será que a classe ObjectInputStream já faz esse tipo de tratamento?
E ai? Alguém sabe uma resposta para esse dilema??

[]'s.

Não recomendo o uso de ObjectInput/OutputStream com sockets.
Já vi gente boa perder o emprego aqui na firma porque insistiu em usar e teve muitos problemas para fazer funcionar (na verdade, nunca funcionou direito e a solução acabou sendo substituída por uma menos orientada a Java).
Use DataInput/OutputStream mesmo, e não se esqueça de dar os “shutdowns” corretos nos sockets.

thingol,
o que seria esse “shutdown”?? Por acaso seria algo relacionado com um flush(), por exemplo??

[]'s.

O “shutdown” em sockets é parecido com o uso daquelas expressões que se usam com rádios portáteis (“Câmbio/Desligo”, ou em inglês “Over” e “Out”.). Você avisa a biblioteca de sockets do seu lado, e do outro lado, que a conexão será fechada.

shutdownInput - indica que você acabou de ler os dados.
shutdownOutput - indica que você acabou de escrever os dados.

Esses “shutdowns” devem ser dados depois do flush e antes do close, mas seu uso deve ser adequado, e só com a prática é que você sabe exatamente quando é que se usa o “shutdownInput” e “shutdownOutput”.

É então… eu já tinha visto um outro post do thingol falando algo parecido…

Ai fiz de tudo aqui, acho que fazem uns 3 dias que estou brigando com isso, cada hora um erro diferente, cada hora numa linha diferente, coisa de maluco…

Ai lembrei do que tinha lido que o thingol falou e não deu outra: DESISTI!
Invés de serializar estou enviando o que preciso num formato XML (numa String) e do outro lado recebo a String e monto o objeto denovo.

Problema resolvido???

Em partes! Funcionar funcionou como é óbvio que funcionaria… então pro meu sistema tudo funciona. Mas, ainda não entendo pq a serialização não funcionava neste caso e em tantos outros que encontrei pela net.

Bem, não vou fechar este tópico por causa disso, se alguém souber explicar o que acontece com a serialização de objetos eu gostaria muito de saber… mas, como já disse, eu contornei meu problema.

Obrigada à todos que ajudaram. :wink:

T+

Agora vou explicar em que condições ObjectInput/OutputStream funcionaria com sockets.

  • Pegue seu objeto.
  • Serialize-o para um array de bytes (usando ByteArrayOutputStream e ObjectOutputStream)
  • Pegue esse array de bytes e mande-o pelo socket, mas não se esqueça de adicionar um header antes dele, para indicar o comprimento do array e mais alguma informação que achar interessante (como um checksum e um indicador de tipo da transação).
  • Do outro lado, leia esses dados do socket, cheque o checksum e outras coisas, e o array de bytes pode ser desconvertido para um objeto usando-se ByteArrayInputStream e ObjectInputStream.)

Você não pode encapsular direto porque dá muitos problemas.