Rapsssito / react-native-tcp-socket

React Native TCP socket API for Android, iOS & macOS with SSL/TLS support.
MIT License
304 stars 80 forks source link

Error sending large messages from Android host #114

Closed acb closed 3 years ago

acb commented 3 years ago

Description

Sometimes when I try to write a large message over the socket (on Android) the server closes the socket without actually writing any data.

Steps to reproduce

My setup is pretty simple, I'm basically just running the TCP server and clients can attempt to connect to it. When they send the server a connection message it responds by sending a big chunk of json encoded data back. The problem is that about 50% of the time I try to connect the server closes the connection without actually writing the data, at least near as I can tell.

My server looks like

import TCP from 'react-native-tcp-socket';
import {Buffer} from 'buffer';

        let server = TCP.createServer((socket) => {
            socket.on('data', (data) => {
                try {
                    data = JSON.parse(data.toString('ascii'));
                } catch (e) { // ignore if not JSON
                    return;
                }

                if(data.message && data.message == "client-setup") {
                    let data = JSON.stringify({
                        key1: <large object>,
                        key2: <large object>,
                        ...
                    });
                    socket.write(Buffer.from(data));
                    socket.end();
                }

            socket.on('error', () => {
                socket.end();
            });
        });

        server.listen({port: PORT, host: this.state.myIpAddress});

and my client is set up like

            client = TCP.createConnection({host: ip, port: PORT}, () => {
                client.write(JSON.stringify({message: "client-setup"}));
            });

            let chunks = [];
            client.on('data', (data) => {
                chunks.push(data);
            });

            client.on("close", () => {
                const data = Buffer.concat(chunks);
                let message = JSON.parse(data.toString());
                <do stuff>
            });

Current behavior

From the debugging that I've been able to do that 50% of the time the client's close handler is called without any data actually getting added to the chunks array, causing a JSON parse error in the close handler. The other 50% of the time it works just fine. There are no errors getting surfaced from the server.

Additionally, this seems to only happen to Android hosts. I've got the same code running on iOS and haven't seen the same issue, leading me to believe it's a problem with the library rather than with my usage of it.

Expected behavior

The server should write out the whole buffer, then close the connection. I'm currently using https://github.com/PeelTechnologies/react-native-tcp with this exact same code and it works as expected. I was hoping to be able to use this library since it's actively maintained.

Relevant information

OS Android 11
react-native 0.63.3
react-native-tcp-socket 5.2.1
Rapsssito commented 3 years ago

@acb, your issue might be related on how react-native-tcp and react-native-tcp-socket handle concurrency. react-native-tcp-socket works more like NodeJS with multiple threads running in the native code to improve performance. However, this might be a bug. Could you try changing your server code to this:

...
        // socket.write(Buffer.from(data));
        // socket.end();
        socket.write(Buffer.from(data), 'utf-8', () => {
            socket.end();
        } );
...
acb commented 3 years ago

@Rapsssito sorry for the slow response, I swear that I had checked this issue in the past 12 days and there wasn't a reply yet, but I guess I just missed it. I tried your change and it seems to work, so thank you! Not a bug, just a difference in the two libraries.