¿Qué tan confiable flush stream de socket () es?

Considere este pedazo de código (simplificado):

public class Test { // assigned elsewhere InetSocketAddress socketAddress; String socketHost; int socketPort; Socket socket; int COMMAND = 10; int CONNECTION_TIMEOUT = 10 * 1000; int SOCKET_TIMEOUT = 30 * 1000; DataOutputStream dos; DataInputStream dis; protected void connect() throws IOException, InterruptedException { socket.connect(socketAddress != null ? socketAddress : new InetSocketAddress(socketHost, socketPort), CONNECTION_TIMEOUT); socket.setSoTimeout(SOCKET_TIMEOUT); socket.setTcpNoDelay(true); } void initializeDataStreams() throws IOException { dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), socket.getSendBufferSize())); dis = new DataInputStream( new BufferedInputStream( socket.getInputStream(), socket.getReceiveBufferSize())); } void run() { try { connect(); initializeDataStreams(); sendCommand(COMMAND, true); sendIdAndUsername(true); sendSyncPreference(true); sendBlockedIds(true); sendHeaders(); // reading from 'dis' here // ... } catch (InterruptedException | IOException e){ /* ... */ } } void sendCommand(int command, boolean buffered) throws IOException { dos.write(command); if (!buffered) { dos.flush(); } } void sendIdAndUsername(boolean buffered) throws IOException { sendId(true); // always buffered String username = "user name"; dos.writeBoolean(username != null); if (username != null) { dos.writeUTF(username); } if (!buffered) { dos.flush(); } } void sendId(boolean buffered) throws IOException { dos.writeUTF("user id"); if (!buffered) { dos.flush(); } } void sendSyncPreference(boolean buffered) throws IOException { boolean fullSync = true; dos.writeBoolean(fullSync); if (!buffered) { dos.flush(); } } void sendBlockedIds(boolean buffered) throws IOException { Set<String> blockedCrocoIds = new HashSet<>(); ObjectOutputStream oos = new ObjectOutputStream(dos); oos.writeObject(blockedCrocoIds); if (!buffered) { oos.flush(); } } private void sendHeaders() throws IOException { dos.writeUTF("some string"); dos.writeInt(123); // some other writes... // this should flush everything, right? dos.flush(); } } 

Lo dejé intencionadamente con todos los métodos, por si acaso he cometido un error terriblemente obvio. Cuando ejecuto Test.run (), a veces (realmente difícil de predecir cuándo exactamente) parece que el color () en sendHeaders () no funciona en absoluto.

El lado del servidor no recibe nada en su ServerSocket.accept () durante los siguientes 22 segundos (no me preguntes de dónde proviene este número, parte del misterio).

La idea era que no llamaría flush () en cada transmisión pero la llamaría solamente una vez, para ahorrar el ancho de banda.

Entonces, ¿qué hay de malo en este código? ¿Cómo asegurar que las escrituras a mi corriente son confiables / inmediatas para que el servidor pueda leerlo lo antes posible?

También acepto la respuesta "no hay nada malo", en ese caso debe ser algo que se está haciendo en paralelo y que afectan a la pila de red en Android.

EDIT: El código del servidor no es nada especial:

 ListeningThread listeningThread = new ListeningThread(); listeningThread.start(); listeningThread.join(); 

y entonces:

 public class ListeningThread extends Thread { private ServerSocket serverSocket; public ListeningThread() { try { // unbound server socket serverSocket = new ServerSocket(); serverSocket.setReuseAddress(true); serverSocket.bind(new InetSocketAddress(NetworkUtil.APP_SERVER_PORT)); } catch (IOException e) { log(e); } } @Override public void run() { log("run"); while (serverSocket.isBound() && !isInterrupted()) { try { Socket socket = serverSocket.accept(); new CommandThread(socket).start(); } catch (IOException e) { log(e); } } try { serverSocket.close(); } catch (IOException e) { log(e); } } } 

y finalmente:

 public class CommandThread extends Thread { private final Socket socket; public CommandThread(Socket socket) { log("CommandThread"); this.socket = socket; } @Override public void run() { log("run"); try { socket.setSoTimeout(NetworkUtil.SOCKET_TIMEOUT); socket.setTcpNoDelay(true); InputStream is = socket.getInputStream(); int cmd = is.read(); // <========= so actually this is failing switch (cmd) { // handling of the command case COMMAND: new DownloadMessagesThread(socket).start(); break; } } catch (IOException | SQLException e) { log(e); } } } 

Como se mencionó en los comentarios, me abriría a ponerse de acuerdo sobre cualquier cosa mal con el objeto streams & co, pero el problema es que no puedo llegar (de nuevo, es sólo a veces, es muy aleatorio …) . Así que a menos que me falte algo más, no hay manera de objetos Streams podría causar este tipo de fracaso.

EDIT 2: Corrección: no es aceptar () No puedo alcanzar, es la primera operación de lectura:

03-07 11: 22: 42.965 00010 CommandThread: CommandThread

03-07 11: 22: 42.966 00108 CommandThread: ejecutar

[… no pasa nada …]

03-07 11: 23: 04.549 00111 DownloadMensajesThread: correr

¿Podría esto ser causado mezclando el flujo del objeto y el flujo de datos después de todo?

    2 Solutions collect form web for “¿Qué tan confiable flush stream de socket () es?”

    Debe comprobar que la creación sendBlockedIds en sendBlockedIds no es el culpable. Ya he tenido algunos "deadlocks" de protocolo al mezclar DataStreams y ObjectStreams, ya que la creación del par Writer / Reader de ObjectStreams implica un tipo de apretón de manos que puede fallar mientras se mezclan esos flujos.

    EDIT: Al leer de nuevo su pregunta, me di cuenta de que no había respondido. Así que sí, es confiable. Y +1 para la respuesta EJP.

    Para responder a la pregunta en su título, es 100% fiable, ya que no hace nada. Sólo los métodos flush() de los flujos que están almacenados en búfer realmente hacen algo, y que sólo incluye ObjectOutputStream y BufferedOutputStream , y PrintStream dependiendo de cómo lo construya. No DataOutputStream , y no el flujo de salida del propio socket.

    Así que en este caso, el único método de descarga que hace algo es el flujo de salida almacenado en búfer, y ciertamente puede confiar en eso, ya que es sólo código, y ha estado trabajando durante veinte años.

    Si esto está afectando a la velocidad de accept() , debe haber algo extraño en su bucle de aceptación que no nos ha mostrado: típicamente, hacer E / S en el bucle de aceptación en lugar de en el hilo iniciado.

    Y ciertamente no debe crear un ObjectOutputStream en medio de la conexión. ObjectInputStream al principio y utilizarlo para todo, y un ObjectInputStream en el otro extremo.

    Nota: la configuración de los tamaños de búfer a los tamaños de búfer de socket, respectivamente, es realmente bastante inútil. Los valores por defecto son adecuados.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.