locked
Wait on a Stream without reading RRS feed

  • Question

  • Hi all,

    I'm writing a library which deals with Streams, and I'm designing a class which represents a generic asynchronous communication peer. I have a loop where I take care of setting up a connection, handling disconnects, synchronizing and so on, leaving the user to implement just the actual protocol.

    To this purpose, I need to be able to wait on a Stream. I can do this with BeginRead, but the problem is that if I do it that way, I need to consume at least one byte from the Stream. I don't like that, because once I know there is data available I want to transfer control to the user program, which should be able to extract all available data from the Stream, including the first byte.

    Is there any way to wait for a Stream to have available data, without actually consuming that data at the same time?

    Note that I'm constrained to .NET 3.5; I can't use the new Async calls from 4.5.

    Thursday, August 30, 2012 2:22 PM

All replies

  • You can extract the buffer the stream uses to determine if there is data.  When you construct a stream class you can either specify the buffer or don't specify the buffer and then the stream class automatically allocates a buffer which can expand as required.  this is a generalization and varies depending on the type of stream you are using.  Some stream types are expandable and other aren't.

    Fro example a memory stream has getbuffer() method.

    http://msdn.microsoft.com/en-us/library/system.io.memorystream.getbuffer.aspx

    You can also get the current position of the stream which will tell you if there is data in the stream.


    jdweng

    Thursday, August 30, 2012 4:16 PM
  • Yes, but if I did it that way I would have to do a busy wait. I can't afford a busy wait. The application needs to respond quickly under load.

    To clarify, I don't need to *know* if the stream has data. That's easy. I need my thread to *wait until* the stream has data, without having to wake up and check every ten millisecs.

    • Edited by Zappo1980 Thursday, August 30, 2012 5:13 PM
    Thursday, August 30, 2012 5:12 PM
  • You don't have to do a read.  I'm not sure if you seen the read call back method.  This uses events to indicate when the connection is established and when the data is available without reading the rx buffer.

    1) First you do a begin read which will wait until the connection is completed

    2) Then you start your callback function.  In the call back function instead of reading data start the user program.  You know if you got to the callback method there is data.  YOu don't have to read.

    See webpage


    jdweng

    Thursday, August 30, 2012 6:33 PM
  • Hi Joel,

    Thanks for your answer. If I understand correctly, you propose to use the AsyncCallback parameter of BeginRead. The problem is that you *must* read data in the callback function, by calling EndRead. The documentation is clear on this. So I have no advantage over Read, as the data will still necessarily end up in my own byte[] and not in the user's.

    Friday, August 31, 2012 7:19 AM
  • The call back function can have one instruction which can be a call to the user program, so technically the user program is part of the call back function.  The end call just closes the connection.  The message processing can all be hadled in the user portion of the code.  Multiple messages can be processed by the user program

    Main Program

    ---------------------------->

    Begin Call

    <-----------------------------

    <-----------------------------

    Receive first message

    --------------------------------------------------> call user program

    <-------------------------------  

    End Call

    --------------------------------->

    User Program

    ------------------------------------------------------------------------------------------------------------------------        

              Read Async

              Process Message

             Send Response

              ------------------------------------------------------------------->

              Wait for command

              <------------------------------------------------------------------

     

              Read Async

              Process Message

             Send Response

              ------------------------------------------------------------------->

              Wait for command

              <------------------------------------------------------------------

              

              Read Async

              Process Message

             Send Response

              ------------------------------------------------------------------->

              Wait for command

              <------------------------------------------------------------------

                        

              


    jdweng

    Friday, August 31, 2012 7:36 AM
  • Thanks for your help Joel. I'll try to describe the problem in another way.

    My library should call a user function when a Stream has data. I have four requirements.

    1) This is the signature of the function: void Process(Stream stream);

    2) The call to Process must only be invoked if the Stream has available data (1 byte is sufficient).

    3) The Process function must be able to access ALL the data that came through the Stream.

    4) No busy wait.

    As near as I can tell, there is no way to satisfy all four requirements at the same time. Your solution requires changing the function signature to something like void Process(byte[] initialData, Stream otherData). That makes things substantially more complex for the user program, which would defeat the purpose of the library.

    Friday, August 31, 2012 8:46 AM
  • Hi Zappo,

    Sorry for delay response.

    >>Your solution requires changing the function signature to something like void Process(byte[] initialData, Stream otherData). That makes things substantially more complex for the user program, which would defeat the purpose of the library.

    Maybe you need to redesign it. Or you can call the library Process(Stream otherData) in "void Process(byte[] initialData, Stream otherData)"

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, September 6, 2012 6:48 AM