How do you make InputStreamOptions.Partial really be partial and not half the buffer size?

Karhu Koti 36 Reputation points
2023-02-22T15:11:32.43+00:00

I am observing that InputStreamOptions.Partial isn't really acting partially, but typically requires 50% of the buffer to be full before it returns.

fyi, this is in a loop:

IBuffer blob = await SerialDeviceConnectedToRadioRX.InputStream.ReadAsync(new Windows.Storage.Streams.Buffer(10), 10, InputStreamOptions.Partial);

More precisely, I have a device that I sent commands to and the device responds back. And, for example, when I send it a 7 byte command, I expect it to be sending me a 7 byte block and then another 8 byte block.

What happens is that when I sent the 7 byte block to the device, the above call correctly gets the 1st 7 byte block I am expecting back AND it gets 3 bytes of the 2nd 8 byte block I am expecting - this is all good. As the loops goes to the 2nd iteration of the call, I expect this to happen:

  • because .Partial is used, the remaining 5 byte block is returned
  • the documentation says:
    Partial 1 The asynchronous read operation completes when one or more bytes is available.

However, the 5 byte block doesn't get returned until a few more bytes are in the buffer (from another command I send out).

From observation, the trigger is about 50% of the buffer size to equate to "partial".

This seems like a bug to me.

I also tried the .ReadAhead and .None and this didn't help the situation.

Thank you for your advice and time.

Universal Windows Platform (UWP)
{count} votes

2 answers

Sort by: Most helpful
  1. Karhu Koti 36 Reputation points
    2023-03-20T17:10:21.3766667+00:00

    The solution is to use: SerialDevice.ReadTimeout = TimeSpan.FromMilliseconds(300);

    Executing the code, the .ReadTimeOut is 0 by default. The documentation says this should wait forever, but it seems with the implementation this is not true if the buffer becomes full or if it becomes 50%+ full.

    So, if the buffer is less than 50% full, you can get the .ReadAsync call to timeout in this manner.

    1 person found this answer helpful.

  2. Anderson Copper 5 Reputation points
    2023-03-15T11:40:25.8366667+00:00

    Based on your description, it sounds like the behavior you are observing may be related to the internal buffering mechanism of the InputStream implementation, rather than a problem with the InputStreamOptions.Partial option itself.

    When you specify InputStreamOptions.Partial, the InputStream.read() method will return as soon as one or more bytes are available in the buffer. However, if there are more bytes available in the buffer than what was requested, the method may return more than the requested number of bytes.

    In your case, it sounds like the first call to InputStream.read() correctly returns the 7-byte block you were expecting, as well as 3 bytes from the next 8-byte block. This suggests that the InputStream implementation is buffering the incoming data and returning it in chunks, rather than immediately passing each byte to your application.

    When you make the second call to InputStream.read() with InputStreamOptions.Partial, it is possible that the buffer already contains more than 5 bytes of data, which is why you are seeing more bytes returned than you were expecting. If the buffer contains fewer than 5 bytes of data, the method will wait until more data is available before returning.

    To work around this issue, you may want to consider using the InputStream.mark() and InputStream.reset() methods to manually manage the amount of data you read from the stream. For example, you could use mark() to mark the current position in the stream before reading the first 7-byte block, and then use reset() to return to that position before reading the next 5-byte block. This would ensure that you only receive the exact amount of data you were expecting, regardless of how the InputStream implementation buffers the incoming data.