views:

63

answers:

3

Hello Everyone,

Let's say I have a url to a streaming data source (for example a stream of updated weather data) and I know this url works with GET (I verified that it does return steaming data). The stream is compressed with GZIP, each "message" begins with a 1 byte id, a 2 byte part containing the message length, then another 2 byte part with some proprietary info. After that comes the message itself, and then this format is repeated as long as the stream remains open.

I need to execute a block of code every time a complete message is received which will parse the raw bytes into .net types (I can figure out the parsing part I'm sure if I have an array of bytes to work with). I've tried endless ways I've found on the net for similar situations but for some reason cannot get this to work. If someone could also explain how to do the same process using POST instead of GET that would be appreciated as well. Thanks in advance everyone!

P.S. From my own attempts at this it appears that only async reading will work. Which is where I think I was falling down in my attempts.

Bob

A: 

What isn't working, exactly? Have you tried getting the response stream with GetResponseStream(), doing a Stream.Read() to a byte[] buffer, and then using BitConverter?

Reinderien
The stream throws an exception that basically says it must be read asynchronously. Its a ConnectStream.
Beaker
"connectstream The stream does not support reading"
Beaker
+1  A: 

Something like:

public IEnumerator<Message> GetEnumerator()
{
    HttpWebRequest req = (HttpWebRequest) WebRequest.Create(uri);
    req.AutomaticDecompression = DecompressionMethods.GZip;
    Stream s = req.GetResponse().GetResponseStream();
    BinaryReader read = new BinaryReader(s);
    while(true)
    {
      byte id = read.ReadByte();
      short len = (short)((read.ReadByte() << 8) | read.ReadByte());
      short proprietary = (short)((read.ReadByte() << 8) | read.ReadByte());
      byte[] msgBytes = read.ReadBytes(len);
      yield return new Message(msgBytes);
    }
}
Matthew Flaschen
Actually that looks pretty good, but I don't think I have ever written my own GetEnumerator method so I'm not sure how I use it in my other code.
Beaker
If what the OP says is true, this will need asynchronous I/O like BeginRead.
Reinderien
This is how I'm using it, please let me know if this is wrong.while(this.GetEnumerator(getUrl).MoveNext()) { byte[] bytes = this.GetEnumerator(getUrl).Current; }When I use it this way it seems to wait forever on this line:byte[] msgBytes = read.ReadBytes(len);
Beaker
BTW, I replaced Message with byte[] in your code.
Beaker
@Beaker, the idea was this would be in a class which had a `uri` instance field and implemented `IEnumerable<Message>`. You could then use a [`foreach`](http://msdn.microsoft.com/en-us/library/ttw7t8t6.aspx) loop to iterate over an instance of the class. If that doesn't make sense, you could change it to a regular method that returns `IEnumerable`, and iterate over the returned value.
Matthew Flaschen
okay, thanks for the effort. Your implementation helped me realize where I was going wrong and then I was able to find the correct solution (the async one).
Beaker
+1  A: 

I found some better search terms and found this question where the answer contained the information I was missing. I was working with IAsyncResult and the request state object incorrectly.

http://stackoverflow.com/questions/295557/c-downloading-a-url-with-timeout

Beaker