Problema com Socket

5 respostas
M

Estou com um problema na utilização de Sockets para envio de um objeto. Apesar de ser possível acessar o servidor utilizando outros sockets (para, por exemplo, cadastro ou login), não estou consigo estabelecer uma conexão com este...
Por algum motivo, quando debugo o programa para verificar onde ocorre o erro, o programa é interrompido ao instanciar o ObjectInputStream na máquina cliente. Não é lançada nenhuma exceção, o programa apenas trava (fora da depuração também trava).

Algoritmo realizado na máquina cliente:
ObjectInputStream in;
    ObjectOutputStream out;
    boolean status;
    int idHistoria;
    Socket cliente;
    public void Comunicacao(int id_Login, History historia) {
        boolean statusEnvio;
        try {
            cliente = new Socket("127.0.0.1", 150);
            in = new ObjectInputStream(cliente.getInputStream()); //Para aqui
            out = new ObjectOutputStream(cliente.getOutputStream());

            out.writeUTF(historia.getName());
            out.writeUTF(historia.getSynopsis());
            out.writeUTF(historia.getAuthor());
            out.writeInt(id_Login);
            out.writeObject(historia);

            statusEnvio = in.readBoolean();
            setEnvio(statusEnvio);
            if(statusEnvio) 
            {
                setIdHistoria(in.readInt());
            }
            in.close();
            out.close();
            cliente.close();

        } catch (IOException stream) {
              stream.printStackTrace();
        }
    }
Algoritmo realizado na máquina servidor:
ServerSocket server;    
 ObjectInputStream in;
 ObjectOutputStream out;
 Socket socket;

try   {        
   server = new ServerSocket(150);
   socket = server.accept();
   
   in = new ObjectInputStream(socket.getInputStream());
   out = new ObjectOutputStream(socket.getOutputStream());

   System.out.println("Recebendo titulo");
   String titulo = in.readUTF();
   setTitulo(titulo);

   System.out.println("Recebendo descricao ");
   String descricao = in.readUTF();
   setDescricao(descricao);

   System.out.println("Recebendo idLogin");
   int idLogin = in.readInt();
   setIdLogin(idLogin);

   System.out.println("Recebendo autor");
   String autor = in.readUTF();
   setAutor(autor);

   try
   {
      System.out.println("Recebendo Objeto");   
      Object history = in.readObject();
      setHistory(history);
   }
   catch(ClassNotFoundException e) {}
 
  
   System.out.println("Conexão estabelecida com o cliente ");
  }
  catch(IOException socketServer) {}
}

Agradeço desde já pela ajuda.

5 Respostas

F

nao vi seu codigo… mas o objeto que você esta tentando enviar e os objetos que o compoe estão implementando a interface Serializable?

P

No seu cliente você possui as seguintes linhas:

in = new ObjectInputStream(cliente.getInputStream()); //Para aqui
out = new ObjectOutputStream(cliente.getOutputStream());

Inverta as mesmas no cliente da seguinte forma:

out = new ObjectOutputStream(cliente.getOutputStream());
in = new ObjectInputStream(cliente.getInputStream()); //Para aqui

Agora o motivo:
Quando você utiliza Sockets você cria uma conexão TCP entre os dois pontos.
Ao chamar o InputStream você tem que “efetivar” esta comunicação.
Então se seu SERVIDOR espera um InputStream, o seu CLIENTE deve chamar o OutputStream, e vice-versa.

Att.

Alexandre Bossa Perotto.

V

Entenda direito o que é um protocolo:

É uma péssima idéia usar ObjectOutputStream para comunicação socket.

P

ViniGodoy ótima postagem, você realmente me salvou muito em outros tópicos e problemas.

Porém me permita discordar do uso do ObjectOutputStream.

Em aplicações com rede o protocolo é extremamente importante e deve ser definido, porém o canal de transmissão que se deseja usar deve atender, é claro, o objetivo do problema.

Em algumas aplicações temos problemas sérios de concorrência pelo canal, isto pede duas medidas: ou uma transmissão de dados de forma única ou um controle avançado.

O que fazemos ao utilizar o ObjectOutputStream na transmissão é tirar do controle da aplicação o controle do tamanho da mensagem transmitida, deixando a cargo da JVM o controle do envio e do recebimento da mesma.

Vamos a um exemplo:
O servidor recebe 2 requisições externas e ambas precisam ser processadas e encaminhadas a um cliente por um único canal.
Enquanto a requisição 1 começa a enviar a requisição 2 se prepara para enviar e começa a trafegar.
O cliente não esperava receber a requisição 2, pois estava recebendo a requisição 1.
Neste caso o ObjectOutputStream resolve o problema de unicidade, pois cada requisição será respondida como um writeObject e lida apenas com um readObject.

OBS: eu sei que a quantidade de leitura pode ser diferente da escrita.

Esta é uma opinião pessoal, sei que usar o ObjectOutputStream não é a melhor solução, mas, ao meu ver, é viável em determinados casos.

V

Essa frase não faz nenhum sentido. Que canal de transmissão? O TCP/IP? E o que isso tem a ver? Em ambas as soluções usa-se o TCP.
Ou por canal você quer dizer o próprio protocolo (que não é um canal de transmissão, mas sim, as regras pelas quais as transmissões ocorrerão no canal)?

E o que isso tem a ver com o que estamos falando?
O ObjectOutputStream não dá qualquer garantia de concorrência sobre o canal, nem faz controle avançado. A única coisa que ele faz é gerenciar sozinho a questão do tamanho do objeto e, ainda assim, ele faz de uma maneira extremamente simplista.

O controle do envio e do recebimento fica a cargo do ObjectOutputStream, não da VM.

Porém, você faz isso perdendo o controle do protocolo, uma vez que você delega ao objeto (em, novamente, não à VM) o papel de se serializar. Isso tem uma implicação grave: se a classe mudar, seu protocolo pode quebrar. E, como você serializará classes da VM e de terceiros, além das suas próprias, implica em dizer que sua aplicação pode quebrar entre duas versões de VM diferentes, ou entre versões de bibliotecas diferentes. Outro problema é que o ObjectOutputStream provavelmente irá serializar muito mais dados do que o necessário para uma comunicação eficiente.

É importante lembrar que numa aplicação de rede existem 2 aplicações se comunicando. E nem sempre essas duas aplicações estarão rodando sobre as mesmas condições (mesma VM, mesma versão dos .jars, etc). Se você amarrar ao ObjectOutputStream, pode ter um custo alto para manter as duas aplicações perfeitamente sincronizadas - o que pode nem sequer ser possível, pois nem sempre você tem controle absoluto do ambiente do cliente. E isso geralmente representa um custo de deploy alto e muito estresse para os usuários finais.

Finalmente, o ObjectOutputStream não implementa qualquer política de Keep Alive. O que significa que se um dos lados saírem da conexão de maneira abrupta, pode levar vários minutos até que o outro perceba.

Criado 12 de novembro de 2012
Ultima resposta 13 de jan. de 2013
Respostas 5
Participantes 4