Search code examples
socketswindows-runtimeuwpwinrt-async

In UWP StreamSocket, can I read data with timeout and leave the connection open if timeout elapses


As I couldn't find any way to peek for data (read data without consuming the buffer) as asked at How to peek StreamSocket for data in UWP apps I'm now trying to make my own "peek" but still no luck.

I don't see how I can read data from StreamSocket in the manner which will let me use timeouts and leave the connection usable in case if timeout elapses.

In the end, the problem is as follows. In my, let's say, IMAP client, I get response from a server and if this response is negative, I need to wait a bit to see if the server immediately sends yet another response (sometimes, the server can do it, with extra details on the error or even a zero packet to close the connection). if the server didn't send another response, I'm fine, just leaving the method and returning to the caller. The caller can then send more data to the stream, receive more responses, etc.

So, after sending a request and getting initial response I need in some cases to read socket once again with a very small timeout interval and if no data arrives, just do nothing.


Solution

  • You can use a CancelationTokenSource to generate a timeout and stop an async operation. The DataReader consumes the data from the input stream of the StreamSocket. Its LoadAsync() method will return when there is at least one byte of data. Here, we are adding a cancellation source that will cancel the asynchronous task after 1 second to stop the DataReader.LoadAsync() if no data has been consumed.

    var stream      = new StreamSocket();
    
    var inputStream = stream.InputStream;
    
    var reader      = new DataReader(inputStream);
    reader.InputStreamOptions   = InputStreamOptions.Partial;
    
    while(true)
    {
        try
        {
            var timeoutSource   = new CancellationTokenSource(TimeSpan.FromSeconds(1));
            var data    = await reader.LoadAsync(1).AsTask(timeoutSource.Token);
    
            while(reader.UnconsumedBufferLength > 0)
            {
                var read    = reader.ReadUInt32();
            }
        }
        catch(TaskCanceledException)
        {
            // timeout
        }
    }
    

    Do no forget that disposing the DataReader will close the stream and the connection.