2014-01-09 2 views
11

Я пытаюсь использовать новый класс HttpClient (в .NET 4.5) для получения частичных ответов с сервера, чтобы проверить содержимое. Мне нужно ограничить размер данных, полученных в первые несколько байтов содержимого в HTTP-запросах, чтобы ограничить использование полосы пропускания.Как получить частичный ответ с System.Net.HttpClient

Я не смог этого сделать. Я попытался использовать GetAsync (url, HttpCompletionOption.ResponseHeadersRead), а затем использовать Content.ReadAsStream(), пытаясь только прочитать заголовки, а затем прочитать поток ответов в небольшом фрагменте. Я также попробовал GetStreamAsync(), а затем прочитал поток Content с небольшим фрагментом (1000 байт).

В обоих случаях оказывается, что HttpClient вытягивает и буферизует весь HTTP-ответ, а не просто считывает запрошенный счетчик байтов из потока.

Первоначально я использовал Fiddler для мониторинга данных, но понял, что Fiddler действительно может вызвать проксирование всего содержимого. Я переключился на использование трассировки System.Net (которая показывает):

ConnectStream#6044116::ConnectStream(Buffered 16712 bytes.) 

, который представляет собой полный размер, а не только прочитанные 1000 байт. Я также дважды проверял в Wireshark, чтобы убедиться, что действительно полный контент натягивается на провод, и это так. С более крупным контентом (например, с каналом 110k) я получаю около 20 тыс. Данных до того, как поток TCP/IP будет усечен.

два пути я попытался прочитать данные:

response = await client.GetAsync(site.Url, HttpCompletionOption.ResponseHeadersRead); 
var stream = await response.Content.ReadAsStreamAsync(); 

var buffer = new byte[1000];           
var count = await stream.ReadAsync(buffer, 0, buffer.Length); 
response.Close() // close ASAP 
result.LastResponse = Encoding.UTF8.GetString(buffer); 

и:

var stream = await client.GetStreamAsync(site.Url); 
var buffer = new byte[1000]; 
var count = await stream.ReadAsync(buffer, 0, buffer.Length); 
result.LastResponse = Encoding.UTF8.GetString(buffer); 

Оба они производят, которые включают буферизованное чтение почти идентично .NET следовых в.

Возможно ли, что HttpClient действительно прочитал только небольшой фрагмент Http Repsonse, а не весь ответ, чтобы не использовать полную полосу пропускания? IOW есть способ отключить любую буферизацию в HTTP-соединении с помощью HttpClient или HttpWebRequest?

Update: После некоторого более обширного тестирования он выглядит как HttpClient и HttpWebRequest буфер первые несколько TCP/IP кадров - предположительно, чтобы обеспечить заголовок HTTP захватывается. Поэтому, если вы возвращаете достаточно маленький запрос, он, как правило, загружается полностью только потому, что он находится в этом inital bufferred read. Но при загрузке большего URL-адреса контента содержимое становится усеченным. Для HttpClient это около 20k, для HttpWebRequest где-то около 8k для меня.

Использование TcpClient не имеет проблем с буферизацией. При его использовании я получаю чтение содержимого с размером прочитанного плюс немного больше для ближайшего перекрытия размера буфера, но это включает заголовок HTTP. Использование TcpClient на самом деле не является для меня вариантом, так как нам приходится иметь дело с сообщениями SSL, Redirects, Auth, Chunked и т. Д. В этот момент я бы посмотрел на реализацию полного пользовательского HTTP-клиента, чтобы включить буферизацию.

+0

Я подозреваю, что вам нужно установить [HttpWebRequest.AllowReadStreamBuffering] (http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowreadstreambuffering%28v=vs.110%29.aspx) свойство 'false'. К сожалению, соответствующие методы в классе «HttpClientHandler» являются «внутренними», поэтому вам нужно будет повторно реализовать весь класс, чтобы установить это свойство. –

+0

Richard, я попробовал использовать необработанный HttpWebRequest и установил эти флаги, но обнаружил, что поведение действительно не изменилось. Согласно Howard Dierking на .NET 4.5 (который я использую), когда вы выбираете опции без буферизации, эти флаги должны автоматически устанавливаться. Может быть, они есть, но это не совсем верно. –

ответ

1

Возможно, я ошибаюсь, но, думаю, вы путаетесь: когда вы отправляете запрос на сервер, он отправит вам полный ответ по сети. Затем он буферизуется где-то через фреймворк, и вы получаете доступ к нему, используя поток. Если вы не хотите, чтобы удаленный сервер отправлял вам полный ответ, вы можете указать диапазон байтов, который вы хотите, используя заголовки http. См. Например, HTTP Status: 206 Partial Content and Range Requests.

+1

Да, я получаю, что сервер отправляет ответ, но клиенту не нужно его читать. Пока клиентский сокет не считывает данные с сервера, нет сетевого трафика :-) Так что, если бы я мог читать необработанный поток, небуферизованный, это позволило бы мне уменьшить фактические байты, перемещающиеся по проводу. Кэширование - вот что завинчивает это. –

+0

И только для того, чтобы уточнить, почему я делаю этот сумасшедший бит: я создаю приложение мониторинга, которое будет проверять * много * произвольных URL-адресов, но для большинства нас будет интересовать только небольшое количество байтов каждого запроса (что-то вроде макс. 2000 байт). Мне нужно свести к минимуму количество данных, которые клиент потребляет, иначе мы будем бить через 100 мегабайт каждые несколько минут. –

+0

Я просто выбрасываю это как догадку, линию запроса, но если полезная нагрузка находится под TcpWindowSize, то не задержит ли она все это одним глотком? –

4

Лучший способ для того чтобы достигнуть того, что вам нужно сделать, это что-то вроде следующего:

using System; 
using System.Net.Sockets; 

namespace tcpclienttest 
{ 
    class Program 
    { 
    static byte[] GetData(string server, string pageName, int byteCount, out int  actualByteCountRecieved) 
    { 
     const int port = 80; 
     TcpClient client = new TcpClient(server, port); 

     string fullRequest = "GET " + pageName + " HTTP/1.1\nHost: " + server + "\n\n"; 
     byte[] outputData = System.Text.Encoding.ASCII.GetBytes(fullRequest); 

     NetworkStream stream = client.GetStream(); 
     stream.Write(outputData, 0, outputData.Length); 

     byte[] inputData = new Byte[byteCount]; 

     actualByteCountRecieved = stream.Read(inputData, 0, byteCount); 

     // If you want the data as a string, set the function return type to a string 
     // return 'responseData' rather than 'inputData' 
     // and uncomment the next 2 lines 
     //string responseData = String.Empty; 
     //responseData = System.Text.Encoding.ASCII.GetString(inputData, 0, actualByteCountRecieved); 

     stream.Close(); 
     client.Close(); 

     return inputData; 
    } 

    static void Main(string[] args) 
    { 
     int actualCount; 
     const int requestedCount = 1024; 
     const string server = "myserver.mydomain.com"; // NOTE: NO Http:// or https:// bit, just domain or IP 
     const string page = "/folder/page.ext"; 

     byte[] myPartialPage = GetData(server, page, requestedCount, out actualCount); 
    } 
    } 
} 

Пара точек отметить, однако:

Там нет обработки ошибок там, так что вы можете захотеть оберните все это в попытке/уловке или что-то, чтобы убедиться, что вы получите какие-либо ошибки соединения, тайм-ауты, нерешенное разрешение IP и т. д.

Избегайте иметь дело с необработанным потоком, тогда также есть заголовки HTTP, поэтому вам нужно принять их во внимание.

Вы могли бы теоретически поставить петлю непосредственно перед чтением основного сокета, продолжая захватывать данные, пока вы не получите пустую \ n на своей собственной линии, которая сообщит вам, где заканчиваются заголовки, тогда вы можете захватите фактическое количество данных, но так как я не знаю сервера, о котором вы тоже говорите, я оставил этот бит :-)

Если вы копируете/вставляете весь код в новый проект консоли в VS, он запускается, поскольку он есть, поэтому вы можете сделать один шаг.

Насколько я знаю, HTTP-клиент не делает его сырым потоком доступным для пользователя, и даже тогда, если он будет создан, поскольку он выделен как потоковое соединение, вряд ли у вас будет большой контроль над его количеством, я «Он изучил это раньше и сдался.

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

Все вопросы, не стесняйтесь ударил меня здесь, или свистеть меня на щебет мою ручку является @shawty_ds (только в случае, если вы его потеряли)

Shawty

+0

PS: 1-я строка должна читать «Привет, Рик», но SO по-прежнему отключает ее! – shawty

+0

Спасибо, что здесь хорошо. К сожалению, TcpClient не будет работать для меня, поскольку мне придется иметь дело с произвольными HTTP-адресами.Могут быть запросы на SSL, запросы на запросы, перенаправления, REST-вызовы с заголовками, данные кодированного контента, SOAP, аутентификация и т. Д., Поэтому на этом низком уровне есть слишком много других вещей. Если бы SSL не был проблемой, я мог бы подумать над этим :-) –

+0

Нет проблем Рик, да, я понимаю, что там целый мир беспорядков. Если я встречу что-нибудь, я обязательно сообщу вам. – shawty

0

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

class Program 
    { 
     static void Main(string[] args) 
     { 
      var host = String.Format("http://{0}:8080/", Environment.MachineName); 
      var server = CreateServer(host); 

      TestBigDownload(host); 

      Console.WriteLine("Done"); 
      server.Dispose(); 
     } 


     private static void TestBigDownload(string host) 
     { 
      var httpclient = new HttpClient() { BaseAddress = new Uri(host) }; 
      var stream = httpclient.GetStreamAsync("bigresource").Result; 

      var bytes = new byte[10000]; 
      var bytesread = stream.Read(bytes, 0, 1000); 
     } 

     private static IDisposable CreateServer(string host) 
     { 
      var server = WebApp.Start(host, app => 
      { 
       var config = new HttpConfiguration(); 
       config.MapHttpAttributeRoutes(); 
       app.UseWebApi(config); 
      }); 
      return server; 
     } 
    } 




    [Route("bigresource")] 
    public class BigResourceController : ApiController 
    { 
     public HttpResponseMessage Get() 
     { 
      var sb = new StringBuilder(); 
      for (int i = 0; i < 10000; i++) 
      { 
       sb.Append(i.ToString()); 
       sb.Append(","); 
      } 
      var content = new StringContent(sb.ToString()); 
      var response = new HttpResponseMessage() 
      { 
       Content = content 
      }; 

      return response; 
     } 
    } 

Logging конфигурации

<system.diagnostics> 
    <sources> 
     <source name="System.Net"> 
     <listeners> 
      <add name="System.Net"/> 
     </listeners> 
     </source> 
    </sources> 
    <switches> 
     <add name="System.Net" value="Verbose"/> 
    </switches> 
    <sharedListeners> 
     <add name="System.Net" 
     type="System.Diagnostics.TextWriterTraceListener" 
     initializeData="network.log" 
     /> 
    </sharedListeners> 
    <trace autoflush="true"/> 
    </system.diagnostics> 

Результирующая журнал

System.Net Information: 0 : [15028] Current OS installation type is 'Client'. 
System.Net Verbose: 0 : [15028] HttpWebRequest#40383808::HttpWebRequest(http://oak:8080/bigresource#-236952546) 
System.Net Information: 0 : [15028] RAS supported: True 
System.Net Verbose: 0 : [15028] Exiting HttpWebRequest#40383808::HttpWebRequest() 
System.Net Verbose: 0 : [15028] HttpWebRequest#40383808::HttpWebRequest(uri: 'http://oak:8080/bigresource', connectionGroupName: '17480744') 
System.Net Verbose: 0 : [15028] Exiting HttpWebRequest#40383808::HttpWebRequest() 
System.Net Verbose: 0 : [25748] HttpWebRequest#40383808::BeginGetResponse() 
System.Net Verbose: 0 : [25748] ServicePoint#45653674::ServicePoint(127.0.0.1:8888) 
System.Net Information: 0 : [25748] Associating HttpWebRequest#40383808 with ServicePoint#45653674 
System.Net Information: 0 : [25748] Associating Connection#41149443 with HttpWebRequest#40383808 
System.Net Verbose: 0 : [25748] Exiting HttpWebRequest#40383808::BeginGetResponse()  -> ContextAwareResult#39785641 
System.Net Information: 0 : [3264] Connection#41149443 - Created connection from 127.0.0.1:10411 to 127.0.0.1:8888. 
System.Net Information: 0 : [3264] Associating HttpWebRequest#40383808 with ConnectStream#39086322 
System.Net Information: 0 : [3264] HttpWebRequest#40383808 - Request: GET http://oak:8080/bigresource HTTP/1.1 

System.Net Information: 0 : [3264] ConnectStream#39086322 - Sending headers 
{ 
Host: oak:8080 
Proxy-Connection: Keep-Alive 
}. 
System.Net Information: 0 : [21384] Connection#41149443 - Received status line: Version=1.1, StatusCode=200, StatusDescription=OK. 
System.Net Information: 0 : [21384] Connection#41149443 - Received headers 
{ 
Content-Length: 48890 
Content-Type: text/plain; charset=utf-8 
Date: Thu, 09 Jan 2014 16:41:59 GMT 
Server: Microsoft-HTTPAPI/2.0 
}. 
System.Net Information: 0 : [21384] ConnectStream#56140151::ConnectStream(Buffered 48890 bytes.) 
System.Net Information: 0 : [21384] Associating HttpWebRequest#40383808 with ConnectStream#56140151 
System.Net Information: 0 : [21384] Associating HttpWebRequest#40383808 with HttpWebResponse#1997173 
System.Net Verbose: 0 : [21384] HttpWebRequest#40383808::EndGetResponse() 
System.Net Verbose: 0 : [21384] Exiting HttpWebRequest#40383808::EndGetResponse() -> HttpWebResponse#1997173 
System.Net Verbose: 0 : [21384] HttpWebResponse#1997173::GetResponseStream() 
System.Net Information: 0 : [21384] ContentLength=48890 
System.Net Verbose: 0 : [21384] Exiting HttpWebResponse#1997173::GetResponseStream() -> ConnectStream#56140151 
System.Net Verbose: 0 : [15028] ConnectStream#56140151::Read() 
System.Net Verbose: 0 : [15028] Data from ConnectStream#56140151::Read 
System.Net Verbose: 0 : [15028] 00000000 : 30 2C 31 2C 32 2C 33 2C-34 2C 35 2C 36 2C 37 2C : 0,1,2,3,4,5,6,7, 
System.Net Verbose: 0 : [15028] 00000010 : 38 2C 39 2C 31 30 2C 31-31 2C 31 32 2C 31 33 2C : 8,9,10,11,12,13, 
System.Net Verbose: 0 : [15028] 00000020 : 31 34 2C 31 35 2C 31 36-2C 31 37 2C 31 38 2C 31 : 14,15,16,17,18,1 
System.Net Verbose: 0 : [15028] 00000030 : 39 2C 32 30 2C 32 31 2C-32 32 2C 32 33 2C 32 34 : 9,20,21,22,23,24 
System.Net Verbose: 0 : [15028] 00000040 : 2C 32 35 2C 32 36 2C 32-37 2C 32 38 2C 32 39 2C : ,25,26,27,28,29, 
System.Net Verbose: 0 : [15028] 00000050 : 33 30 2C 33 31 2C 33 32-2C 33 33 2C 33 34 2C 33 : 30,31,32,33,34,3 
System.Net Verbose: 0 : [15028] 00000060 : 35 2C 33 36 2C 33 37 2C-33 38 2C 33 39 2C 34 30 : 5,36,37,38,39,40 
System.Net Verbose: 0 : [15028] 00000070 : 2C 34 31 2C 34 32 2C 34-33 2C 34 34 2C 34 35 2C : ,41,42,43,44,45, 
System.Net Verbose: 0 : [15028] 00000080 : 34 36 2C 34 37 2C 34 38-2C 34 39 2C 35 30 2C 35 : 46,47,48,49,50,5 
System.Net Verbose: 0 : [15028] 00000090 : 31 2C 35 32 2C 35 33 2C-35 34 2C 35 35 2C 35 36 : 1,52,53,54,55,56 
System.Net Verbose: 0 : [15028] 000000A0 : 2C 35 37 2C 35 38 2C 35-39 2C 36 30 2C 36 31 2C : ,57,58,59,60,61, 
System.Net Verbose: 0 : [15028] 000000B0 : 36 32 2C 36 33 2C 36 34-2C 36 35 2C 36 36 2C 36 : 62,63,64,65,66,6 
System.Net Verbose: 0 : [15028] 000000C0 : 37 2C 36 38 2C 36 39 2C-37 30 2C 37 31 2C 37 32 : 7,68,69,70,71,72 
System.Net Verbose: 0 : [15028] 000000D0 : 2C 37 33 2C 37 34 2C 37-35 2C 37 36 2C 37 37 2C : ,73,74,75,76,77, 
System.Net Verbose: 0 : [15028] 000000E0 : 37 38 2C 37 39 2C 38 30-2C 38 31 2C 38 32 2C 38 : 78,79,80,81,82,8 
System.Net Verbose: 0 : [15028] 000000F0 : 33 2C 38 34 2C 38 35 2C-38 36 2C 38 37 2C 38 38 : 3,84,85,86,87,88 
System.Net Verbose: 0 : [15028] 00000100 : 2C 38 39 2C 39 30 2C 39-31 2C 39 32 2C 39 33 2C : ,89,90,91,92,93, 
System.Net Verbose: 0 : [15028] 00000110 : 39 34 2C 39 35 2C 39 36-2C 39 37 2C 39 38 2C 39 : 94,95,96,97,98,9 
System.Net Verbose: 0 : [15028] 00000120 : 39 2C 31 30 30 2C 31 30-31 2C 31 30 32 2C 31 30 : 9,100,101,102,10 
System.Net Verbose: 0 : [15028] 00000130 : 33 2C 31 30 34 2C 31 30-35 2C 31 30 36 2C 31 30 : 3,104,105,106,10 
System.Net Verbose: 0 : [15028] 00000140 : 37 2C 31 30 38 2C 31 30-39 2C 31 31 30 2C 31 31 : 7,108,109,110,11 
System.Net Verbose: 0 : [15028] 00000150 : 31 2C 31 31 32 2C 31 31-33 2C 31 31 34 2C 31 31 : 1,112,113,114,11 
System.Net Verbose: 0 : [15028] 00000160 : 35 2C 31 31 36 2C 31 31-37 2C 31 31 38 2C 31 31 : 5,116,117,118,11 
System.Net Verbose: 0 : [15028] 00000170 : 39 2C 31 32 30 2C 31 32-31 2C 31 32 32 2C 31 32 : 9,120,121,122,12 
System.Net Verbose: 0 : [15028] 00000180 : 33 2C 31 32 34 2C 31 32-35 2C 31 32 36 2C 31 32 : 3,124,125,126,12 
System.Net Verbose: 0 : [15028] 00000190 : 37 2C 31 32 38 2C 31 32-39 2C 31 33 30 2C 31 33 : 7,128,129,130,13 
System.Net Verbose: 0 : [15028] 000001A0 : 31 2C 31 33 32 2C 31 33-33 2C 31 33 34 2C 31 33 : 1,132,133,134,13 
System.Net Verbose: 0 : [15028] 000001B0 : 35 2C 31 33 36 2C 31 33-37 2C 31 33 38 2C 31 33 : 5,136,137,138,13 
System.Net Verbose: 0 : [15028] 000001C0 : 39 2C 31 34 30 2C 31 34-31 2C 31 34 32 2C 31 34 : 9,140,141,142,14 
System.Net Verbose: 0 : [15028] 000001D0 : 33 2C 31 34 34 2C 31 34-35 2C 31 34 36 2C 31 34 : 3,144,145,146,14 
System.Net Verbose: 0 : [15028] 000001E0 : 37 2C 31 34 38 2C 31 34-39 2C 31 35 30 2C 31 35 : 7,148,149,150,15 
System.Net Verbose: 0 : [15028] 000001F0 : 31 2C 31 35 32 2C 31 35-33 2C 31 35 34 2C 31 35 : 1,152,153,154,15 
System.Net Verbose: 0 : [15028] 00000200 : 35 2C 31 35 36 2C 31 35-37 2C 31 35 38 2C 31 35 : 5,156,157,158,15 
System.Net Verbose: 0 : [15028] 00000210 : 39 2C 31 36 30 2C 31 36-31 2C 31 36 32 2C 31 36 : 9,160,161,162,16 
System.Net Verbose: 0 : [15028] 00000220 : 33 2C 31 36 34 2C 31 36-35 2C 31 36 36 2C 31 36 : 3,164,165,166,16 
System.Net Verbose: 0 : [15028] 00000230 : 37 2C 31 36 38 2C 31 36-39 2C 31 37 30 2C 31 37 : 7,168,169,170,17 
System.Net Verbose: 0 : [15028] 00000240 : 31 2C 31 37 32 2C 31 37-33 2C 31 37 34 2C 31 37 : 1,172,173,174,17 
System.Net Verbose: 0 : [15028] 00000250 : 35 2C 31 37 36 2C 31 37-37 2C 31 37 38 2C 31 37 : 5,176,177,178,17 
System.Net Verbose: 0 : [15028] 00000260 : 39 2C 31 38 30 2C 31 38-31 2C 31 38 32 2C 31 38 : 9,180,181,182,18 
System.Net Verbose: 0 : [15028] 00000270 : 33 2C 31 38 34 2C 31 38-35 2C 31 38 36 2C 31 38 : 3,184,185,186,18 
System.Net Verbose: 0 : [15028] 00000280 : 37 2C 31 38 38 2C 31 38-39 2C 31 39 30 2C 31 39 : 7,188,189,190,19 
System.Net Verbose: 0 : [15028] 00000290 : 31 2C 31 39 32 2C 31 39-33 2C 31 39 34 2C 31 39 : 1,192,193,194,19 
System.Net Verbose: 0 : [15028] 000002A0 : 35 2C 31 39 36 2C 31 39-37 2C 31 39 38 2C 31 39 : 5,196,197,198,19 
System.Net Verbose: 0 : [15028] 000002B0 : 39 2C 32 30 30 2C 32 30-31 2C 32 30 32 2C 32 30 : 9,200,201,202,20 
System.Net Verbose: 0 : [15028] 000002C0 : 33 2C 32 30 34 2C 32 30-35 2C 32 30 36 2C 32 30 : 3,204,205,206,20 
System.Net Verbose: 0 : [15028] 000002D0 : 37 2C 32 30 38 2C 32 30-39 2C 32 31 30 2C 32 31 : 7,208,209,210,21 
System.Net Verbose: 0 : [15028] 000002E0 : 31 2C 32 31 32 2C 32 31-33 2C 32 31 34 2C 32 31 : 1,212,213,214,21 
System.Net Verbose: 0 : [15028] 000002F0 : 35 2C 32 31 36 2C 32 31-37 2C 32 31 38 2C 32 31 : 5,216,217,218,21 
System.Net Verbose: 0 : [15028] 00000300 : 39 2C 32 32 30 2C 32 32-31 2C 32 32 32 2C 32 32 : 9,220,221,222,22 
System.Net Verbose: 0 : [15028] 00000310 : 33 2C 32 32 34 2C 32 32-35 2C 32 32 36 2C 32 32 : 3,224,225,226,22 
System.Net Verbose: 0 : [15028] 00000320 : 37 2C 32 32 38 2C 32 32-39 2C 32 33 30 2C 32 33 : 7,228,229,230,23 
System.Net Verbose: 0 : [15028] 00000330 : 31 2C 32 33 32 2C 32 33-33 2C 32 33 34 2C 32 33 : 1,232,233,234,23 
System.Net Verbose: 0 : [15028] 00000340 : 35 2C 32 33 36 2C 32 33-37 2C 32 33 38 2C 32 33 : 5,236,237,238,23 
System.Net Verbose: 0 : [15028] 00000350 : 39 2C 32 34 30 2C 32 34-31 2C 32 34 32 2C 32 34 : 9,240,241,242,24 
System.Net Verbose: 0 : [15028] 00000360 : 33 2C 32 34 34 2C 32 34-35 2C 32 34 36 2C 32 34 : 3,244,245,246,24 
System.Net Verbose: 0 : [15028] 00000370 : 37 2C 32 34 38 2C 32 34-39 2C 32 35 30 2C 32 35 : 7,248,249,250,25 
System.Net Verbose: 0 : [15028] 00000380 : 31 2C 32 35 32 2C 32 35-33 2C 32 35 34 2C 32 35 : 1,252,253,254,25 
System.Net Verbose: 0 : [15028] 00000390 : 35 2C 32 35 36 2C 32 35-37 2C 32 35 38 2C 32 35 : 5,256,257,258,25 
System.Net Verbose: 0 : [15028] 000003A0 : 39 2C 32 36 30 2C 32 36-31 2C 32 36 32 2C 32 36 : 9,260,261,262,26 
System.Net Verbose: 0 : [15028] 000003B0 : 33 2C 32 36 34 2C 32 36-35 2C 32 36 36 2C 32 36 : 3,264,265,266,26 
System.Net Verbose: 0 : [15028] 000003C0 : 37 2C 32 36 38 2C 32 36-39 2C 32 37 30 2C 32 37 : 7,268,269,270,27 
System.Net Verbose: 0 : [15028] 000003D0 : 31 2C 32 37 32 2C 32 37-33 2C 32 37 34 2C 32 37 : 1,272,273,274,27 
System.Net Verbose: 0 : [15028] 000003E0 : 35 2C 32 37 36 2C 32 37-      : 5,276,27 
System.Net Verbose: 0 : [15028] Exiting ConnectStream#56140151::Read() -> Int32#1000 
+0

Ведение журнала показывает только реальную платформу .NET Framework в входном буфере, но она ничего не говорит нам о фактических данных, поступающих по проводу. Появляется (не может подтвердить), что что-то предварительно загружает кусок данных даже до того, как мы начнем читать из буфера ответа - к моменту, когда я вызываю ReadStream(), на провод уже есть трафик контента. –

+0

@RickStrahl Еще одна вещь, чтобы рассмотреть. Вы можете отправить SendAsync() с помощью ResponseHeadersRead, а затем немедленно отменить запрос. Это должно прервать HttpWebRequest. Это может свести к минимуму количество байтов, проходящих через провод. –

0

Я думаю/надеюсь, что это может помочь.

How can I perform a GET request without downloading the content?

Как я и подозревал, что нижележащие слои будут тянуть больше, чем вы хотите, несмотря на то, что .NET видит.

Update

Хотя HttpWebRequest.AddRange(-256) получит первые 256 байт, то кажется, что будет работать только для статического файла на IIS.

Он устанавливает заголовок Range (не путать с If-Range).

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2

Сервер рекламирует его поддерживает запросы диапазона, используя заголовок Accept-Ranges.

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

Альтернативой может быть установка ReceiveBufferSize на ServicePoint, который выставлен на WebRequest.

+1

Yup Я использую Range, но, как вы указываете, он просто не будет работать во всем - только там, где сервер поддерживает его (статический контент или какой-то модуль). Мое содержание будет произвольным. Я попытался изменить req.ServicePoint.ReceiveBufferSize, но это буквально не повлияло - TCP/IP по-прежнему кажется буферизирующим около 20k при первом чтении. –

+0

Рик кажется щекой, чтобы спросить об этом 3 1/2 года, но ... Вы когда-нибудь решали это? :-) –

Смежные вопросы