Search code examples
javaandroidsocketsdataoutputstream

DataOutputStream: dos.write() in loop, Receiver receives only one data package


I have a problem with my TCP connection. I send data (a simple string) via a smartphone to a tablet by a TCP socket connection. The connection works fine and data is transmitted as expected. But when I do a loop and in every iteration dos.write() is fired only one packages arrive on the tablets data receiver. What am I doing wrong?

Here's the sending part of my connection. It iterates through the list and writes every data to the DataOutputStream.

for(int i = 0; i <= logList.length - 1; ++i){
    String backupPayload = invertLogStringToJson(logList[i]);

    dos = new DataOutputStream(s.getOutputStream());

    dos.writeUTF(backupPayload);
    dos.flush();
    dos.close();

On the tablet I receive the data via this code snippet:

@Override
public void run() {
    try {

        while(true){
            mySocket = ss.accept();
            dis = new DataInputStream(mySocket.getInputStream());
            message = dis.readUTF();

            handler.post(() -> {
                bufferIntentSendCode.putExtra("data", message);
                ctx.sendBroadcast(bufferIntentSendCode);
            });
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

As I said the connection works fine when I send only one data package. But if I want to send multiple packages inside the loop only the first package will arrive at the destination.

Can anyone help me? :)


Solution

  • Calling close() on a DataOutputStream closes its associated OutputStream, and closing a socket's OutputStream closes the socket. This is documented behavior.

    But, that should be OK, because your receiver code is only expecting to receive 1 single string anyway. You are calling dis.readUTF() only one time per TCP connection.

    If you want to send multiple strings in a single connection, DON'T call dos.close() on the sending side (at least until all of the strings have been sent), and DO call dis.readUTF() in a loop on the receiving end until all strings have been received.

    dos = new DataOutputStream(s.getOutputStream());
    
    for(int i = 0; i < logList.length; ++i){
        String backupPayload = invertLogStringToJson(logList[i]);
        dos.writeUTF(backupPayload);
    }
    dos.flush();
    
    dos.close();
    
    @Override
    public void run() {
        try {
            while (true) {
                mySocket = ss.accept();
                dis = new DataInputStream(mySocket.getInputStream());
    
                try {
                    while (true) {
                        message = dis.readUTF();
                        handler.post(() -> {
                            bufferIntentSendCode.putExtra("data", message);
                            ctx.sendBroadcast(bufferIntentSendCode);
                        });
                    }
                } catch (IOException e) {
                }
    
                dis.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    Alternatively, send the list length before sending the actual strings, and then read the length before reading the strings:

    dos = new DataOutputStream(s.getOutputStream());
    
    // maybe other things first...
    
    dos.writeInt(logList.length);
    for(int i = 0; i < logList.length; ++i){
        String backupPayload = invertLogStringToJson(logList[i]);
        dos.writeUTF(backupPayload);
    }
    dos.flush();
    
    // maybe other things next...
    
    dos.close();
    
    @Override
    public void run() {
        try {
            while (true) {
                mySocket = ss.accept();
                dis = new DataInputStream(mySocket.getInputStream());
    
                try {
                    // maybe other things first...
    
                    int length = dis.readInt();
                    for (int i = 0; i < length; ++i) {
                        message = dis.readUTF();
                        handler.post(() -> {
                            bufferIntentSendCode.putExtra("data", message);
                            ctx.sendBroadcast(bufferIntentSendCode);
                        });
                    }
    
                    // maybe other things next...
    
                } catch (IOException e) {
                }
    
                dis.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }