2012-04-15 10 views
5

Mi pregunta se encuentra en los siguientes supuestos que espero que es verdadero, porque creo que estos como los leo, mientras que buscando en Google mis problemas:¿Cómo se puede forzar una descarga en un objeto OutputStream sin cerrarlo?

  1. Cierre OutputStream de un Socket cierra el socket método demasiado
  2. El flush() de OutputStream no hace nada

Así que, básicamente, necesito eliminar todos los datos de mi objeto OutputStream para que mi aplicación funcione.

Si usted está interesado en los detalles, por favor, consulte los siguientes enlaces: dos

. Weird behavior : sending image from Android phone to Java server (code working)

Este problema se resolvió al cerrar OutputStream. Al hacerlo, se volcaron todos los datos en el otro extremo del socket e hicieron que mi aplicación funcionara más, pero esta corrección pronto dio lugar al problema número 2: el socket correspondiente también se cierra:

. SocketException - 'Socket is closed' even when isConnected() returns true

+2

Si estás bajoneando, ten la decencia de explicar por qué. – GrowinMan

Respuesta

1

Cierre OutputStream de un Socket cierra el socket demasiado

verdadera.

El método flush() de OutputStream no hace nada

Falso. Hay reemplazos Consulte el Javadoc para FilterOutputStream.flush(), BufferedOutputStream.flush(), ObjectOutputStream.flush(), por nombrar algunos.

Así que su problema inicial es inexistente, por lo que no necesita la 'solución' que causa el problema # 2.

+0

Pero entonces, ¿qué propones para el problema n. ° 1? Inicialmente usé flush() en lugar de close() sobre OutputStream pero la imagen no se transfirió entonces .. – GrowinMan

+0

La solución para el problema n. ° 1 no es cerrar la secuencia. Si el interlocutor necesita el final del flujo para saber cuándo se completa un mensaje, está utilizando un protocolo de aplicación que solo permitirá un mensaje. e, entonces necesitas cambiarlo. No hay mensajes en TCP, solo una secuencia de bytes. Los mensajes son tu decisión. – EJP

+0

ras no hacer nada - downvote ver mi respuesta – ceph3us

6

Puede llamar al método de descarga de OutputStream en lugar de cerrar. Las clases concretas heredadas de OutputStream anularán a flush() para hacer algo que no sea nada (escribir los datos en un archivo o enviarlos a través de la red).

+0

Pero si ves la primera pregunta que me envió, la imagen transferida sobre el zócalo no consigue transferido hasta el OutputStream está cerrado. Y usar flush() no ayuda allí. ¿Qué sugieres allí entonces? – GrowinMan

+3

En el enlace que ha publicado, el servidor está esperando un EOF (fin de archivo) en la transmisión. Un EOF se señala cerrando el flujo y la conexión TCP, por lo que el servidor se ejecuta en el ciclo hasta que cierre el flujo de salida en el lado del cliente. Si no desea cerrar la transmisión después de transferir la imagen, tiene que idear otro método para señalizar cuando se complete la transferencia de imágenes. La forma más sencilla de hacerlo es enviar el tamaño de la imagen como un entero (4 bytes) antes de enviar la imagen. Entonces, el servidor puede leer esa cantidad de bytes antes de salir del ciclo. – smichak

2

El método flush() de OutputStream no hace nada.

Esto es incorrecto.

Es cierto que la implementación base de flush() proporcionada por la clase OutputStream no hace nada. Sin embargo, su aplicación llamará a la versión de ese método proporcionada por real clase de flujo que está utilizando. Si la clase de flujo no tiene semántica de escritura directa, anulará flush() para hacer lo que se requiere.

En resumen, si se requiere un color (y es requerido para un flujo de salida de socket), a continuación, llamar a flush() va a hacer lo correcto. (Si alguna fuente de internet te dice lo contrario, es incorrecto o lo estás malinterpretando).)


FYI, la razón por la que la base OutputStream implementos flush() como un no-op es que:

  • alguna salida clases de flujo no tienen que hacer nada cuando tiraba; por ejemplo, ByteArrayOutputStream y
  • para las clases de flujo donde flush() no es una operación no operativa, no hay forma de implementar la operación en el nivel de clase base.

Podrían (en teoría) han hecho diseñadas las API de transmisión de modo que OutputStream era una clase abstracta (y flush() un método abstracto) o una interfaz. Sin embargo, esta API se congeló efectivamente antes de Java 1.0, y en ese momento no había suficiente experiencia con la programación práctica de Java para darse cuenta de que el diseño de la API no era óptimo.

0

¿Realmente necesita enjuagar? También tuve un problema, donde el oyente en el servidor C# no podía recibir los datos enviados desde Android (traté de obtener los datos de forma sincrónica).

Estaba seguro de que esto es porque en el lado de Android, el siguiente código no funcionaba.

OutputStream str = btSocket.getOutputStream(); 
str.write(data_byte); 
// "This implementation does nothing" 
str.flush(); 

Resultó, que si uso la recuperación de datos asincrónica de escucha del servidor - que obtiene los datos, y no se requiere flush() en el lado del cliente!

0

Haré una puñalada. Estaba teniendo el mismo problema. cerrar el outputtream es la única forma en que puedo "vaciar" los datos. pero como todavía necesito la salida de salida, esa no es una opción. así que primero envío la longitud de la matriz de bytes, out.writeInt, luego la matriz misma. cuando todos los bytes se han leído es decir buffer.length == in.readInt() i de rotura de lazo

ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream(); 
    byte[] buffer = new byte[1024]; 
    byte[] fileBytes; 
    int n; 
    int length; 

    try 
    { 
     size = in.readInt(); 

     while((n = in.read(buffer)) != -1) 
     { 
      dataBuffer.write(buffer, 0, n); 

      if(dataBuffer.toByteArray().length == length) 
      { 
       fileBytes = dataBuffer.toByteArray(); break; 
      } 
     } 
    } 
0

que tenía el mismo problema. Agrega "\ n" al final de la transmisión. obras ras, pero la destinary no sabe si el mensaje terminó

0

SÍ a ras Android() no hacen nada (ejemplo basado en la API 23)

public Socket() { 
    this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl(); 
    this.proxy = null; 
} 

public class PlainSocketImpl extends SocketImpl { 

    @Override protected synchronized OutputStream getOutputStream() throws IOException { 
     checkNotClosed(); 
     return new PlainSocketOutputStream(this); 
    } 


} 

private static class PlainSocketOutputStream extends OutputStream { 
     // doesn't override base class flush(); 
} 

para vaciar flujo de salida sin cerrar conexión de la que puede apagar salida:

protected void shutdownOutput() throws IOException 

- esto cerrará descriptor de archivo de escritura.

en lugar de utilizar la corriente de salida se puede escribir directamente en el descriptor de archivo o mediante la creación propia implementación de cubo de OutputStream que reemplazar el método flush (por ejemplo usando una aplicación Berkeley socket en C (a través de llamada nativa).

Cuestiones relacionadas