This project has moved. For the latest updates, please go here.

Strange freeze in networkstream.read

Topics: Bluetooth - Microsoft
Aug 20, 2012 at 4:53 PM

I am having trouble with reading a bluetooth stream in my Windows Form app
using .net 4.0. I am reading from a device that, after initial configuration,
starts sending data in a continuous stream of 11 byte packets.
My stream reading occurs in a bacground thread with AboveNormal priority. My
read loop looks like so:  
int x;
int p = 0;
byte[] bytes = new byte[len];
ulong st = (ulong)Environment.TickCount;
ulong tm = st + 5000;
ulong tt = 0;
do
{
    while ((!m_Stream.DataAvailable) && ((ulong)Environment.TickCount < tm)) ;
    x = 0;
    if (m_Stream.DataAvailable)
        x = m_Stream.Read(bytes, 0, len - p);
    tt = (ulong)Environment.TickCount - st;
    if (x > 0)
    {
        if (tt > 1000) Debug.WriteLine("Waited " + tt.ToString() + " ticks for " + x.ToString() + " characters");
        Array.Copy(bytes, 0, buf, p, x);
        p += x;
    }
    else
    {
        Debug.WriteLine("Wait for data avail timed out after " + ((ulong)Environment.TickCount - st).ToString());
    }
} while ((x > 0) && (p < len));

Elsewhere I am watching to make sure a buffer overrun isn't threatening and
I take measures if so. But my code is fast enough that it is never more than
a packet or two behind.
Things go swimmingly for about 6 seconds and then I get a message from the
routine above that it had to wait 3600 milliseconds for 1 character. If I
immediately check client.Available it reports hundred of characters in the
stream. So the read is blocking (or being blocked) somehow even though
characters are building up in the stream.
Any ideas? 

Ron

Aug 20, 2012 at 7:02 PM

Oh, I should add that after a few minutes of these failures and recoveries, I eventually get an IOException and the stream becomes inactive.

           -- Ron

Developer
Aug 21, 2012 at 8:16 AM

What platform? Win32 with Microsoft stack? Or something else?

What happens if you have a very simple loop that simple does a blocking read successively?

  while(true) {
     int readLen = strm.Read(...);
     Console.WriteLine("read num bytes: " + readLen);
     if(readLen==0) break;
  }

Aug 21, 2012 at 6:50 PM

I am on an x64 Windows 7 machine -- an ASUS laptop -- and I'm pretty sure its using the Microsoft stack. The program is a .net 4.0 Windows Form application. Hardware is Atheros.

I'll try the test you suggest -- except one thing I've noticed is that the stream read does not ever seem to block (except for this unfortunate case). It will return with a 0 count immediately if no characters are available even though the connection is (and remains) open. That runs contrary to the documented behavior, but that is how its behaving.

I have not set any value into the ReadTimeout property. I wonder if I did, whether that would give the class back its documented behavior. Hmmm....

                    -- Ron

Aug 21, 2012 at 7:20 PM
Edited Aug 21, 2012 at 7:25 PM

FYI: setting the ReadTimeout did not change the stalling out behavior but it did get rid of the 0 length return from stream.Read.

My revised and simplified loop:

            m_Stream.ReadTimeout = 5000; // 5 second timeout
            int x;
            int p = 0;
            byte[] bytes = new byte[len];
            do
            {
                 x = m_Stream.Read(bytes, 0, len - p);
                 if (x > 0)
                 {
                     Array.Copy(bytes, 0, buf, p, x);
                     p += x;
                 }
             } while (x > 0 && p < len);

Developer
Aug 22, 2012 at 8:19 AM

So is behaving acceptably now?

 

Note on your code. There shouldn't be need for the copy, just pass the current buffer position to Read's second parameter.

byte[] buf = ... // ??? new byte[len];
int totalRead = 0;
do
{
    int readLen = m_Stream.Read(buf, totalRead, len - totalRead);
    totalRead += readLen;
} while (readLen > 0 && totalRead < len);

If you want to print timing you could use BeginRead/EndRead e.g.

byte[] buf = ... // ??? new byte[len];
int totalRead = 0;
do
{
    var start = Environment.TickCount;
    var ar = m_Stream.BeginRead(buf, totalRead, len - totalRead, null, null);
    int readLen = m_Stream.EndRead(ar);
    var delta = Environment.TickCount - start;
    Debug.WriteLine("t: " + delta);
    totalRead += readLen;
} while (readLen > 0 && totalRead < len);

.

Aug 22, 2012 at 8:38 PM

Thanks for the help. But I still can't seem to get rid of this behavior no matter what I do. The problem is strikingly similar to the problem stated here: http://stackoverflow.com/questions/1965553/networkstream-read-delay-net.

And I see a number of discussion threads that feature the words Pause or Freeze with NetworkStream.Read, but I really have not found a solution which seems to fit.

I backed off this and did an implementation with Franson, but it exhibited the same behavior. So you are off the hook. :-)

Thanks again for all the help.

Ron

Developer
Aug 23, 2012 at 9:40 AM

The blocks aren't being coalesced are they? Is the x (readLen) value much large than expected immediately before or after one of the pauses?

Aug 23, 2012 at 12:40 PM

Whenever there has been a long delay I am logging a line like this:

Debug.WriteLine("Waited " + tt.ToString() + " ticks for " + x.ToString() + " characters with "+m_Client.Available.ToString()+" available");

What I see after a Read that has blocked is a large number of bytes in the queue -- over a hundred, sometimes over 200. The amount seems to correlate with the blocking time as the device I am reading transmits continuously. And due to the various testing I've done, I know that the number of bytes available in the queue prior to the blocking read was less than 22 (because my packet size is 11, and if there were bytes for two or more packets I read past the the first packets to get the the last full packet available).

Aug 23, 2012 at 12:53 PM

Come to think of it, I know that prior to the delayed read the queue was actually empty. If I spin on DataAvailable prior to every read, the delay is still manifested but the Read itself never blocks.