2008-10-06 15 views
6

Creé un ObjectInputSteam y ObjectOutputStream en un bloqueo SocketChannel y estoy tratando de leer y escribir al mismo tiempo. Mi código es algo como esto:Java: ¿Son posibles las lecturas y escrituras simultáneas en un SocketChannel de bloqueo a través de Object (In | Out) putStreams?

socketChannel = SocketChannel.open(destNode); 
objectOutputStream = new ObjectOutputStream(Channels.newOutputStream(socketChannel)); 
objectInputStream = new ObjectInputStream(Channels.newInputStream(socketChannel)); 

Thread replyThread = new Thread("SendRunnable-ReplyThread") { 
    @Override 
    public void run() { 
     try { 
      byte reply = objectInputStream.readByte();//(A) 
      //..process reply 
     } catch (Throwable e) { 
      logger.warn("Problem reading receive reply.", e); 
     } 
    } 
}; 
replyThread.start(); 

objectOutputStream.writeObject(someObject);//(B) 
//..more writing 

problema es la introducción de información en línea (B) bloquea hasta que la lectura en la línea (A) completa (bloques en el objeto devuelto por SelectableChannel#blockingLock()). Pero la lógica de la aplicación dicta que la lectura no se completará hasta que todas las escrituras se completen, por lo que tenemos un punto muerto efectivo.

SocketChannel javadocs dicen que las lecturas y escrituras concurrentes son compatibles.

que no experimentaron ningún problema de este tipo cuando intenté una solución zócalo periódica:

Socket socket = new Socket(); 
socket.connect(destNode); 
final OutputStream outputStream = socket.getOutputStream(); 
objectOutputStream = new ObjectOutputStream(outputStream); 
objectInputStream = new ObjectInputStream(socket.getInputStream()); 

Sin embargo, entonces no puedo aprovechar las ventajas de rendimiento de FileChannel#transferTo(...)

Respuesta

1

Si desea utilizar InputStream y OutputStream simultáneamente con SocketChannel, al mirar la fuente, parece que necesita llamar a SocketChannel.socket() y usar las secuencias de eso que se comportan de forma ligeramente diferente.

+0

He intentado cambiarlo para usar socketChannel.socket(). Get (Out | In) putStream, pero no hizo ninguna diferencia. El OutputStream parece ser del mismo tipo que antes: la clase interna anónima devuelta por Channels # newOutputStream (OutputStream). –

+0

Es el InputStream que debería cambiar a una subclase (no probado). –

+4

* comprueba bugster * http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=d76c6fabad9827be488fceb8d9f4?bug_id=4509080 Muchos errores, baja prioridad. Parece que estás obligado a comenzar con una vieja escuela java.net.Socket. –

2

Esto parece ser un error en java.nio.channels.Channels (gracias a Tom Hawtin, publíquelo como respuesta la próxima vez). Una buena descripción y una solución se describen here (en realidad un duplicado del error Tom en la lista):

He probado la solución alternativa y funciona.

0

¡Error interesante! Sin embargo, dices que no puedes usar FileChannel # transferTo. ¿Qué hay de envolver las secuencias de E/S del socket que no es NIO en los canales utilizando Channesl # newChannel antes de pasar a FileChannel # transferTo?

+0

Creo que 'transferTo' solo tiene beneficios de rendimiento si el' WritableByteChannel' es una verdadera clase de NIO para la cual tiene soporte específico, no un contenedor de una clase de IO regular. No estoy seguro, aunque –

+0

Ahora que lo pienso, me pregunto si el ajuste de SocketChannel en un ByteChannel ficticio según la solución alternativa descrita en una de las otras respuestas también obviará los beneficios de rendimiento de transferencia a. –

2

La solución en el informe de error funcionó para mí. Vale la pena señalar que solo de entrada o salida debe completarse para que la solución funcione, por lo que si el rendimiento es especialmente importante en una dirección, puede envolver la menos importante y asegurarse de que la otra obtenga todas las optimizaciones disponible para ello.

public InputStream getInputStream() throws IOException { 
    return Channels.newInputStream(new ReadableByteChannel() { 
     public int read(ByteBuffer dst) throws IOException { 
      return socketChannel.read(dst); 
     } 
     public void close() throws IOException { 
      socketChannel.close(); 
     } 
     public boolean isOpen() { 
      return socketChannel.isOpen(); 
     } 
    }); 
} 

public OutputStream getOutputStream() throws IOException { 
    return Channels.newOutputStream(socketChannel); 
} 
Cuestiones relacionadas