Skip to content Skip to sidebar Skip to footer

Tcp Client For Android: Text Is Not Received In Full

I am converting a Java desktop project to Android. Part of it includes a TCP connection to a server and parsing a long text from the server to the client (the Android application).

Solution 1:

Let talk about TCP socket first.

When talking about TCP socket, it's a stream of data. TCP views data as an unstructured, but ordered, stream of bytes. It's different from the kinds of socket.io.

From time to time, TCP will grab chunks of data from the send buffer and pass the data to the network layer. The maximum amount of data that can be grabbed and placed in a segment is limited by the maximum segment size (MSS). The MSS is typically set by first determining the length of the largest link-layer frame.

So it depends on the device.

For example, you have two messages, each of them has 1000 bytes data, and you call:

-------------- client side ----------------

client.send(theFirstMessage) // 1000 bytes
client.send(theSecondMessage) // 1000 bytes

-------------- server side -----------------

socket.onReceived(data => {
    // process(data)
})

With above pseudocode you should note that:

The data which received and called on onReceived block couldn't be 1000 bytes of theFirstMessage.

  1. It could be first 400 bytes, then on other event you receive 400 bytes, then more 400 bytes (200 of the first one and 200 of the second one).
  2. It could be 1200 bytes (1000 of the first one and 200 of the second one).

TCP views data as an unstructured, but ordered, stream of bytes. Socket.io is a wrapper, when it uses TCP socket, it collect and combine/split the data for you, so that you received the events with exactly the data was sent from other side. When you work with TCP, you have to do it your self, you have to define the application protocol to do it.

There're two common ways to send/receive TCP requests:

  1. Splitter, you choose a splitter. For example, we choose 32 bits AABBCCDD as the splitter (same as you choose END_DATA string), but keep in mind it's binary data. Then you have to ensure that the data in request doesn't contains the splitter. To do that, you have to encode the request. For example we can encode request as base64, then use the character which isn't included in base64 table as the splitter.

  2. Prefix length, the above method has its overhead as we have to encode request data. The prefix length method is a better choice. We can prefix the length of request before.

The pseudocode:

// use Int32, 4 bytes to indicate the length of message after it

-------------- client side ----------------
    client.send(theFirstMessage.length)    // Int32
    client.send(theFirstMessage) // 1000 bytes
    client.send(theSecondMessage.length) 
    client.send(theSecondMessage) // 1000 bytes


-------------- server side -----------------

    var buffer = Buffer()
    socket.onReceived(data => {
        buffer.append(data)
        let length = Int32(buffer[0...3])
        if (buffer.length >= length + 4) {
           let theRequest = buffer[4 ... 4 + length - 1]
           process(theRequest)
           buffer = buffer.dropFirst(4 + length)
        }
    })

One more thing, when working with TCP socket, it's just stream of bytes, so the endianness is important https://en.wikipedia.org/wiki/Endianness

For example, an android device is little endian and server side (or other android device) is big endian. Then 4 bytes of Int32 from the android device, when received on server side, it will be decoded wrongly if you don't care about it.

So, the prefix length should be encoded by specific endianness.

Post a Comment for "Tcp Client For Android: Text Is Not Received In Full"