DataReader for SocketStream for UWP app

I've seen a few questions like this, but so far I haven't seen a real solution that works for the UWP platform.

I am connecting to some UPnP devices on the network that are sending JSON back on port 1255. I have an initial connection working and a send request that tells the devices to send me some information.

StreamSocket socket;
using (socket = new StreamSocket())
{
    hostName = new HostName("192.168.0.nnn");
    await socket.ConnectAsync(hostName, "1255");
    //Code that does the request for info
    await this.read();
}

public async Task<String> read()
{
    string runStr = "";
    uint inBufferCnt = 0;

    using (reader = new DataReader(socket.InputStream))
    {
        reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.ReadAhead;
        reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
        reader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;

        inBufferCnt = await reader.LoadAsync(256); //InBuffer is always 256, 
            //even if there is more data waiting. If I put a task.delay in it will always return 256

        while (reader.UnconsumedBufferLength > 0)
        {
            var iRead = reader.ReadString(reader.UnconsumedBufferLength);
            runStr = runStr + iRead;
            inBufferCnt = await reader.LoadAsync(64); //always hangs here. 
                //Even if I reduce to 1, it will sit waiting for new data
        }
...

      

Everything works fine until the last LoadAsync. Although there is data in the stream, as long as it is less than 64 bytes, it will rotate around the While loop. If it's less than that, then it just sits there, waiting for more data. So there might be 50 bytes in the buffer which I can't get. In the above example, inBufferCnt is always the exact size of the value passed to LoadAsync.

I've tried different things like adding a timeout, but I can't access anything else after the exception is thrown, so I still don't know how much data is in the stream.

CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(5000);
...
inBufferCnt = await reader.LoadAsync(64).AsTask(cts.Token);

      

I do not know how much data I will return from the device, I have no control over the communication of the device (other than requesting information). I think I read half of the web page looking for a solution, but I can't seem to find anything that directly relates to this particular problem.

So the main question is: "How are you supposed to read from the socket stream, and then when there is no more data (at this time), just return what is sitting in the current stream. The buffer waiting to be read."

Reference...

0


source to share


1 answer


I do not know how much data I will return from the device, I have no control over the communication of the device (other than requesting information). So the main question is, "How should you read from a socket stream, and then when there is no more data (at this time), just return what is in the current stream. The buffer can be of any size to read."

As per your description, I found a solution for you:

First, set the read parameters for the input stream Partially .

reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial;

      



Thus, an asynchronous read operation completes when one or more bytes are available. So the asynchronous read operation sits and waits for new data only , when there is not any bytes available, then you can add a timeout to handle this situation as you mentioned above.

CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(5000);
...
inBufferCnt = await reader.LoadAsync(sizeToReadEachTime).AsTask(cts.Token);

      

Below is some sample Ive code:

public async Task<String> read()
{
    string runStr = "";
    uint inBufferCnt = 0;
    //size of bytes to load each time.
    uint sizeToReadEachTime = 256;
    CancellationTokenSource cts = new CancellationTokenSource();
    //set timeout here.
    cts.CancelAfter(5000);

    using (reader = new DataReader(socket.InputStream))
    {
        //set the read options for the input stream to Partial.
        reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial;
        reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
        reader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;

        while (true)
        {
            try
            {
                //add a timeout for the asynchronous load operation.
                inBufferCnt = await reader.LoadAsync(sizeToReadEachTime).AsTask(cts.Token);
                runStr += reader.ReadString(inBufferCnt);
            }
            catch (System.Threading.Tasks.TaskCanceledException)
            {
                //load operation will get timeout only when there is no data available.
                cts.Dispose();
                break;
            }
        }

        reader.DetachStream();
    }
    return runStr;
}

      

-1


source







All Articles