Попытка асинхронно читать бесконечный поток байтов в C # - PullRequest
2 голосов
/ 14 октября 2010

Я подключаюсь к серверу, который отправляет обновления о финансовой информации.Код, который я выкладываю ниже, будет работать правильно в течение нескольких минут, а затем обычно срывается, когда он пытается выполнить EndRead (где я отметил), потому что в тот момент было 0 байтов для чтения.Очевидно, что в финансовом мире некоторые вещи могут оставаться неизменными в течение нескольких минут или более, что, кажется, является источником моей проблемы.Также я подозреваю, что есть лучший способ сделать это, чем то, что я показываю ниже.Если у вас есть более эффективный или элегантный способ добиться того же результата, я весь слух.В основном код, который у меня сейчас есть, собран из случайных фрагментов кода здесь и в других местах.Я просто не могу найти образец, который собирает все части так, как мне нужно.

Заранее спасибо,

Боб

Редактировать: я должен был иметьпояснил, что я в основном понимаю, что происходит, я просто не могу найти причину закрытия потока.Я думаю, что лучшим ответом будет другая реализация, которая делает то же самое.Я пытался заставить WebClient сделать это, но мне не повезло.

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.response = (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;
    }

Ответы [ 4 ]

0 голосов
/ 25 февраля 2014

Http - это неправильный протокол для того, чего вы пытаетесь достичь, соединение закрывается после каждого запроса.Либо используйте TCP напрямую, либо просто опросите.

0 голосов
/ 14 октября 2010

Согласно документации, IOException генерируется, только если поток закрыт. Похоже, что соединение с сокетом было отключено, а сокет закрыт.

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

Я предлагаю вам отследить ошибку и заново открыть соединение.

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

0 голосов
/ 03 ноября 2013

.NET Framework 4 / 4.5 имеет встроенные оптимизированные асинхронные HttpClient классы.Вы можете использовать их для достижения почти всего, что вы хотите от 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);
}
0 голосов
/ 14 октября 2010

0 байт означает, что поток завершен.Методы APM не имеют тайм-аута, и в документации четко указано, что чтение нулевых байтов означает, что соединение закрыто.

Потоки возвращают ноль (0) только в конце потока

Вы уверены, что устраняете неисправности в нужном месте?IOException почти наверняка содержит больше информации, которая была бы полезна.

...