2011-12-04 36 views
7


Estoy programando una clase para comunicarme con un servidor, pero cuando trata de construir ObjectInputStream con la ayuda de inputstream el programa se congela. No hay Excepción y el programa todavía se está ejecutando, pero está colgando en la línea donde intenta construir el ObjectInputstream.ObjectInputStream (socket.getInputStream()); no funciona

Aquí está el código del método donde se encuentra mi problema:

@Override 
public void connect(String ip, int port) throws UnknownHostException, IOException { 
    Socket socket = new Socket(ip, port); 
    out = new ObjectOutputStream(socket.getOutputStream()); 
    InputStream is = socket.getInputStream(); 
    in = new ObjectInputStream(is); 
} 

y este es el código para toda la clase:

package Client; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.PrintWriter; 
import java.net.Socket; 
import java.net.UnknownHostException; 


public class MessageStreamerImpl implements MessageStreamer { 
    ObjectOutputStream out; 
    ObjectInputStream in; 

    public MessageStreamerImpl(String ip, int port) throws UnknownHostException, IOException{ 
     connect(ip, port); 
    } 

    public MessageStreamerImpl(){ 
    } 

    @Override 
    public void send(Object message) throws IOException { 
     if(out == null) throw new IOException(); 
     out.writeObject(message); 
     out.flush(); 
    } 

    @Override 
    public Object receive() throws IOException{ 
     try { 
      return in.readObject(); 
     } catch (ClassNotFoundException e) { 
      throw new IOException(); 
     } 
    } 

    @Override 
    public void connect(String ip, int port) throws UnknownHostException, IOException { 
     Socket socket = new Socket(ip, port); 
     out = new ObjectOutputStream(socket.getOutputStream()); 
     InputStream is = socket.getInputStream(); 
     in = new ObjectInputStream(is); 
    } 

} 

Mientras observa Google encontré esto: http://www.coderanch.com/t/232944/threads/java/Socket-getInputStream-block. Pero todavía no sé cómo resolver el problema, porque mi constructor ObjectOutputStream está antes que el de ObjectInputStream.

Aquí está mi código del servidor, tal vez va a ayudar;)

package Server; 

import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.net.SocketException; 
import java.util.ArrayList; 

public class Server { 
    ArrayList<Socket> clients = new ArrayList<Socket>(); 

    public Server(int port){ 
     try { 
      ServerSocket mySocket = new ServerSocket(port); 
      waitForClients(mySocket); 
     } catch (IOException e) { 
      System.out.println("Unable to start."); 
      e.printStackTrace(); 
     } 
    } 

    private void waitForClients(ServerSocket mySocket) { 
     while(true){ 
      try { 
       System.out.println("Ready to receive"); 
       Socket client = mySocket.accept(); 
       clients.add(client); 
       System.out.println(client.getInetAddress().getHostAddress()+" connected to the Server"); 
       Thread t = new Thread(new ClientHandler(client)); 
       t.start(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 

    public void shareToAll(Object objectToSchare){ 
     for(Socket client:clients){ 
      ObjectOutputStream oos; 
      try { 
       oos = new ObjectOutputStream(client.getOutputStream()); 
       oos.writeObject(objectToSchare); 
       oos.close(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 

    private class ClientHandler implements Runnable{ 
     Socket clientSocket; 

     public ClientHandler(Socket clientSocket){ 
      this.clientSocket = clientSocket; 
     } 
     @Override 
     public void run() { 
      try { 
       ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream()); 
       while(true){ 
        try { 
         ois.readObject(); 

        } catch (ClassNotFoundException | IOException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
      }catch(SocketException e){ 
       System.out.println(clientSocket.getInetAddress().getHostAddress()+" disconnected from the Server"); 
       clients.remove(clientSocket); 
      }catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

Gracias por su ayuda he encontrado la falla. Fue en la clase de servidor que tiene que tener este aspecto:

package Server; 

import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.net.SocketException; 
import java.util.ArrayList; 

public class Server { 
    ArrayList<ObjectOutputStream> clientstreams = new ArrayList<ObjectOutputStream>(); 

    public Server(int port){ 
     try { 
      ServerSocket mySocket = new ServerSocket(port); 
      waitForClients(mySocket); 
     } catch (IOException e) { 
      System.out.println("Unable to start."); 
      e.printStackTrace(); 
     } 
    } 

    private void waitForClients(ServerSocket mySocket) { 
     while(true){ 
      try { 
       System.out.println("Ready to receive"); 
       Socket client = mySocket.accept(); 
       clientstreams.add(new ObjectOutputStream(client.getOutputStream())); 
       System.out.println(client.getInetAddress().getHostAddress()+" connected to the Server"); 
       Thread t = new Thread(new ClientHandler(client)); 
       t.start(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 

    public void shareToAll(Object objectToSchare){ 
     for(ObjectOutputStream stream:clientstreams){ 
      try { 
       stream.writeObject(objectToSchare); 
       stream.flush(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 

    private class ClientHandler implements Runnable{ 
     Socket clientSocket; 

     public ClientHandler(Socket clientSocket){ 
      this.clientSocket = clientSocket; 
     } 
     @Override 
     public void run() { 
      try { 
       ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream()); 
       while(true){ 
        try { 
         ois.readObject(); 

        } catch (ClassNotFoundException | IOException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
      }catch(SocketException e){ 
       System.out.println(clientSocket.getInetAddress().getHostAddress()+" disconnected from the Server"); 
       clientstreams.remove(clientSocket); 
      }catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

Los mayoría de los cambios que se ven en las waitForClients método(), pero he cambiado, también el concepto de mi ArrayList y el método shareToAll.

Respuesta

12

el constructor ObjectInputStream lee datos del InputStream proporcionado. para que esto funcione, debe vaciar el ObjectOutputStream inmediatamente después de la construcción (para escribir el encabezado inicial) antes de intentar abrir el ObjectInputStream. Además, si desea enviar más de un objeto por conexión, debe abrir ObjectOutputStream una vez y usarlo durante toda la vida útil del socket (por ejemplo, su método shareToAll).

+0

No sé si tuviste lo mismo, pero encontré el motivo. El faul estaba en la clase de servidor en el método waitForClients() Tengo que generar un Outputstream después de Socket client = mySocket.accept(); con client.getOutputstream() ;. De lo contrario, el cliente está bloqueado esperando el OutputStream (su InputStream). Gracias –

+0

Edité la pregunta, porque todavía no puedo responder mis propias preguntas. –

+0

aún no debería redefinir las transmisiones de entrada y salida cada vez. Deben ser globales dentro de la clase 'ClientHandler'. – Jon