Leitura em Sockets

(Ignore a falta de acentos, teclado americano aqui…)

Pessoal, estou desenvolvendo uma aplicacao para palm, que se comunica com uma aplicacao servidor em desktop.

Como j2me e meio limitado nao tem o ObjectImput/Output Stream, entao estou desenvolvendo a serializacao e comunicacao usando Sockets e DataImputStream mesmo.

So que estou tendo problemas em uma parte, eu consigo serializar e deserializar uma clase basica, mas quando tento fazer a mesma coisa com outra classe, da guru…

Eu sei que a classe Message tem 8 bytes, entao na outra ponta eu uso o metodo read passando 8 bytes, ele le certinho, e eu consigo deserializar ela no cliente. Entretanto, tenho uma classe Package, na qual tem um array de bytes de tamanho variavel, estou tentando fazer assim.

Envio a classe message, que contem um integer correspondente ao tipo de mensagem (ex: ESTOU_LHE_ENVIANDO_UM_CLIENTE, ESTOU_FECHANDO_O_SOCKET), e um integer, contendo o tamanho do “pacote” que posso lhe enviar, no caso, se eu mandei uma mensagem do tipo “load_client” com tamanho 37, o cliente deve estar preparado para ler o socket, buscando 37 bytes, e converter esse objeto em um cliente.

So far, so good? Ok…

Isso tem funcionado com a classe Message, na qual eu sei que eu tenho 2 integers pra ler, o problema que isso na classe com tamanho variavel tem viajado demais, quando eu deserializo, ela vem toda esculhambada, acredito que mesmo eu enviando o tamanho do pacote, e tentando ler, ele deve estar lendo um byte a mais ou a menos (ja tentei mandar ele ler 1000 bytes, e ele retorna dizendo que so conseguiu ler exatamente o que eu tinha mandado ele ler), e na hora de deserializar logicamente vai badernar tudo. A questao eh, como eu faco para ler um array de bytes via sockets, se eu nao sei o tamanho? Porque se tiver como, eu posso nao especificar o tamanho a ser lido, que eu acho que esta ai o problema. Segue abaixo o codigo usado.

Classe package

import bean.Serializable;

public class Package implements Serializable {

	private Integer dataSize;
	private byte[] data;
	
	public Package() {
		
	}
	
	public Package(Integer dataSize, byte[] data) {
		this.dataSize = dataSize;
		this.data = data;
	}

        // metodo que serializa o objeto em um array de bytes para ser transferido
	@Override
	public byte[] serialize() {
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		try {
			DataOutputStream dout = new DataOutputStream(bout);

			dout.write(this.dataSize.intValue());
			dout.write(this.data);
			dout.flush();
		} catch(IOException e) {
			e.printStackTrace();
		}		
		return bout.toByteArray();

	}
	
        // esse, deserializa: pega o array que foi recebido na conexao, e popula os campos
        // vejam que eu uso o tamanho do pacote
	@Override
	public void deserialize(byte[] data) {
		try {
			ByteArrayInputStream bin = new ByteArrayInputStream(data);
			DataInputStream din = new DataInputStream(bin);

			this.dataSize = din.readInt();
			this.data = new byte[this.dataSize];
			din.read(this.data);
		} catch(IOException e) {
			e.printStackTrace();
		}

	}
	
		
}

Aqui, como e feito o envio, vejam que eu mando uma Message antes passando o tamanho do pacote que sera enviado a seguir

public void loadClients() {
		List<Client> list = Client.loadClients();
		for(Client c: list) {
                        // serializo o objeto cliente, da mesma maneira que a classe Package 
                        // Claro que pode haver problema na serializacao/deserializacao do cliente, mas lembrando que 
                        // o problema esta em serializar->transferir->deserializar a classe Package, mesmo que
                        // o conteudo do array do cliente possa vir a chegar errado, ao menos, ele tem 
                        // que chegar em primeiro lugar.
			byte[] data = c.serialize();
                        // enviando uma message, dizendo que vou enviar um cliente, e que o pacote tera data.length
			sendMessage(Message.SEND_CLIENT, data.length);
                        // crio/envio um pacote, passando data.length (usado na deserializacao) e data (logicamente)
			sendPackage(data.length, data);
		}
		
	}

aqui, o codigo que envia, e no caso do socket cliente, o codigo que recebe o pacote logo abaixo
A proposito, ‘dos’ e ‘dis’ sao DataInput/OutputStreams, obtidos durante o ‘openSocket’ e que foram passadas pelo construtor para a classe que executa esses metodos.

public void sendPackage(Integer packageSize, byte[] data) {
		try {
			Package p = new Package(packageSize, data);
			dos.write(p.serialize());
			dos.flush();
		} catch(IOException e) {
			e.printStackTrace();
		}		
	}
	
	public Package receivePackage(Integer packageSize) {
		Package p = new Package();
		byte[] ba = new byte[packageSize.intValue()];
		try {
			int size = dis.read(ba);
		} catch (IOException e) {
			e.printStackTrace();
		}
		p.deserialize(ba);
		return p;
	}

Quando o metodo p.deserialize(ba) e chamado, ele viaja legal, pois o dataSize da classe package deveria vir 33 bytes, e ta vindo tipo… 500000+ bytes, dai da out of memory…

Alguem sabe o que eu posso estar fazendo de errado, ou alguem tem uma sugestao de uma mulher “framework” para troca de dados via sockets? Lembrando que nao posso usar frameworks prontos (a nao ser que sejam especificos do JME, senao nao funciona na KVM), nem classes como ObjectImputStream, visto que tambem nao estao presentes na KVM. A nao ser que alguem saiba como implementar essa classe com a api J2ME.

Se voce teve paciencia em ler ate aqui, ja fico agradecido =D

Edit: Tirando um pouco de codigo, pra nao poluir

Andre Trevisani

O método write, assim como o método read, aceitam também 2 parâmetros adicionais (início e quantidade de dados a transmitir/receber).

Pois e, tentei assim tambem, e mesmo especificando pra ele ler da posicao 0, tamanho packageSize, da erro. Vou tentar chumbar o tamanho do pacote (no caso desse, 33 bytes, e cumbar 31, 32, 34 e 35 so por garantia), ainda nao tinha tentado ler com esse metodo chumbando o numero de bytes a ler… vamos ver se funciona

Eh, nao funcionou, ele continua dizendo que leu 33 bytes, dai eu peco pra ele deserializar, e os dados vem corrompidos. Nao sei se e o codigo de serializacao/deserializacao que ta errado, ou sei la…

Já tentou usar o wireshark para ver de que lado da conexão está o problema?

Pode ser que já esteja saindo do cliente corrompido, ou pode ser que o servidor esteja corrompendo na hora de ler…

Qual dos dois é seu caso?

Acredito que na hora de ler esta o problema. Vou dar uma olhada nesse wireshark, nunca usei. Vamos ver se consigo descobrir o problema, dai posto aqui.
Valeu!

Tenta analisar um código sem nem imprimir os valores das suas variaveis.
É como tentar achar um erro em redes sem o wireshark. :slight_smile: