Search code examples
node.jssocketsnetwork-programmingwindows-store-appsuwp

Failed to Receive Data via sockets from Node.js to UWP app


I have a problem i am try reading via sockets a string in uwp app from a node.js server with no success. I got an System.Runtime.InteropServices.COMException and i dont know how to fix it. I manage to send with succes from the uwp client to the node server a string but i can't do the opposite. Here is my code what i am doing wrong?

This is my node.js Server Code

var _HOST = '192.168.1.67';
    var _PORT = 1337;
    var _address;

    var net = require('net');

    var server = net.createServer(function(socket) {
        socket.on('connect', (e) => {
            console.log('client connected ' +
                socket.remoteAddress + ':' +
                socket.remotePort);
        });

        socket.on('data', function(data) {
            console.log('clients says' + ': ' + data);

            var send = "hello client"
            console.log('Server says' + ': ' + send);
            socket.write(send + '\n');


        });

        socket.on('error', function(data) {
            console.log('client on error', data);

        });

        socket.on('close', (e) => {
            console.log('client disconnected');
            socket.end;
        });

    });

This is my UWP Code

  public async Task connect()
        {


            try
            {
                HostName hostName;

                hostName = new HostName(SocksParameters.Host);
                socket.Control.NoDelay = false;
                var cts = new CancellationTokenSource();
                cts.CancelAfter(SampleConfiguration.timeout);

                // Connect to the server
                var connectAsync = socket.ConnectAsync(hostName, SocksParameters.Port);
                var connectTask = connectAsync.AsTask(cts.Token);
                await connectTask;
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.ToString());
                await new MessageDialog("Make sure your Server is open and make sure you follow Instructions To connect localhost").ShowAsync();
                Application.Current.Exit();
            }

        }

public async Task<String> read()
        {
            DataReader reader;
            StringBuilder strBuilder;



            using (reader = new DataReader(socket.InputStream))
            {

                try
                {
                    strBuilder = new StringBuilder();
                    reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial;

                    reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
                    reader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;

                    await reader.LoadAsync(256);
                    while (reader.UnconsumedBufferLength > 0)
                    {
                        strBuilder.Append(reader.ReadString(reader.UnconsumedBufferLength));
                        await reader.LoadAsync(256);//System.Runtime.InteropServices.COMException Exception caught
                    }

                    reader.DetachStream();
                    return strBuilder.ToString();
                }
                catch (Exception e)
                {    
                    return (e.ToString());

                }
            }

        }

  Activated Event   Time    Duration    Thread
    Exception thrown: 'System.Runtime.InteropServices.COMException' in mscorlib.ni.dll ("The I/O operation has been aborted because of either a thread exit or an application request.

The I/O operation has been aborted because of either a thread exit or an application request.
")  0.55s       [18700] <No Name> 

Solution

  • I tested the code and I found if there is no more data can be read by the DataReader object reader, the code line await reader.LoadAsync(256); will always wait there until new messages send from server and DataReader can read it. In the code of yours if the size of coming data from server is less than 256, the second time you invoke the LoadAsync method may lead issues.

     await reader.LoadAsync(256);
     while (reader.UnconsumedBufferLength > 0)
     {
         strBuilder.Append(reader.ReadString(reader.UnconsumedBufferLength));     
         await reader.LoadAsync(256);
          //System.Runtime.InteropServices.COMException Exception caught
     }
    

    The workaround I provided here is to judge whether there is data left can be read. Updated code as follows:

     var loadsize = await reader.LoadAsync(256);
     while (loadsize >= 256)
     {
         loadsize = await reader.LoadAsync(256);
     }
     if (reader.UnconsumedBufferLength > 0)
     {
         strBuilder.Append(reader.ReadString(reader.UnconsumedBufferLength));
     }
    

    In my opinion, it seems like you can use StreamReader which is also work for your scenario instead of DataReadersince it is more simply to use. Code like follows:

    Stream streamIn = socket.InputStream.AsStreamForRead();
    StreamReader reader = new StreamReader(streamIn);
    string response = await reader.ReadLineAsync();
    return response;
    

    More details about StreamSocket in uwp please reference the official sample.