开发者

Trying to read non-ending byte stream asynchronously in C#

I am connecting to a server which sends updates about financial information. The code I post below will work correctly for a few minutes then usually blows up when it tries to do an EndRead (where I have noted), because there was 0 bytes at that moment to be read. Obviously in the financial world some things can stay the same price for a few minutes or more which seems to be the source of my problem. Also I suspect there is a better way to do this than what I am showing below. If you have a more efficient or elegant way to achieve the same result I am all ears. Basically the code I have now is assembled from random snippets of code from here and elsewhere. I just can't seem to find a sample that puts all the pieces together the way I need them.

Thanks in advance,

Bob

Edit: I should have clarified that I basically understand what is going wrong, I just can't find the reason why the stream is being closed. I think the best answer will be a different implementation that does the same thing. I tried making WebClient do this but didn't have any luck with that.

public IAsyncResult BeginStreamingData()
    {
        postUrl = "https://" + "myfinancialbytestreamsource.com/";
        byte[] buffer = Encoding.ASCII.GetBytes(postdata);
        HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(postUrl);
        httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip;
        httpWebRequest.Method = "POST";
        httpWebRequest.ContentType = "application/x-www-form-urlencoded";
        httpWebRequest.ContentLength = buffer.Length;
        httpWebRequest.Timeout = 6000000;
        httpWebRequest.ReadWriteTimeout = 6000000;
        Stream PostData = httpWebRequest.GetRequestStream();
        PostData.Write(buffer, 0, buffer.Length);
        PostData.Close();

        IAsyncResult result =
          (IAsyncResult)httpWebRequest.BeginGetResponse(new AsyncCallback(ResponseCallback), new AsyncState
          {
              request = httpWebRequest
          });

        return new CompletedAsyncResult<string>("Completed stream.");
    }

internal void ResponseCallback(IAsyncResult asynchronousResult)
    {
        AsyncState state = asynchronousResult.AsyncState as AsyncState;
        HttpWebRequest httpWebRequest = state.request;
        state.r开发者_如何学Cesponse = (HttpWebResponse)httpWebRequest.EndGetResponse(asynchronousResult);

        Stream responseStream = state.response.GetResponseStream();
    byte[] buffer = new byte[1024 * 10];

    var completedEvent = new ManualResetEvent(false);

    responseStream.BeginRead(buffer, 0, buffer.Length,
                            AsyncRead,
                            new AsyncState
                            {
                                b = buffer,
                                s = responseStream,
                                e = completedEvent
                            });

    completedEvent.WaitOne();
    }

private void AsyncRead(IAsyncResult ar)
    {
        AsyncState state = ar.AsyncState as AsyncState;
        int read = 0;

//BLOWS UP HERE (IOException) WHEN IT ENDS A READ THAT HAD 0 BYTES IN IT.

read = state.s.EndRead(ar);

            if (read == 0)
            {
                // signal completion
                state.e.Set();
                return;
            }
            else
            {
                //this is where I'm parsing the bytes into .net objects.
                ParseBytes(state.b, read);

            }
            // read again
            state.s.BeginRead(state.b, 0, state.b.Length, AsyncRead, state);
    }

//Here is the class that stores the state.
private class AsyncState
    {
        public Stream s;
        public ManualResetEvent e;
        public byte[] b;
        public HttpWebRequest request;
        public HttpWebResponse response;
    }


According per documentation, IOException is only thrown if the stream is closed. So it appears that the socket connection has been disconnected and socket is closed.

IOException 
The stream is closed or an internal error has occurred.

I suggest you track the error and re-open the connection.

http://msdn.microsoft.com/en-us/library/system.io.stream.endread.aspx


0 bytes means the stream has ended. The APM methods do not timeout, and the documentation clearly states that a read of zero byes indicates that the connection is closed.

Streams return zero (0) only at the end of the stream

Are you sure you're troubleshooting in the right place? The IOException almost certainly contains more info which would be useful.


.NET Framework 4/4.5 have built-in optimized async HttpClient classes. You can use them to achieve almost all that you want from HTTP.

var responseMessage = await (new HttpClient().GetAsync("http://download.linnrecords.com/test/flac/recit24bit.aspx", HttpCompletionOption.ResponseHeadersRead));
if (responseMessage.StatusCode == System.Net.HttpStatusCode.OK)
{
    var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test_http_download.flac");
    using (var fileStream = File.Create(filePath))
    using (var httpStream = await responseMessage.Content.ReadAsStreamAsync())
    {
        httpStream.CopyTo(fileStream);
        fileStream.Flush();
    }
    Process.Start(filePath);
}


Http is the wrong protocol for what you are trying to achieve, the connection is closed after each request. Either use TCP directly or just poll.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜