即使使用了'HttpCompletionOption.ResponseHeadersRead',HttpClient在哪里存储响应?

3
即使像这样使用HttpCompletionOption.ResponseHeadersRead
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://myserver.com");

var request = new HttpRequestMessage(HttpMethod.Get, "huge_file.bin");
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

一旦调用了SendAsync,HttpClient就会发出一个GET请求。这可以在Fiddler中看到。
在底层,底层的HttpClient实际上将请求响应存储在哪里?它是存储在内存中吗?如果是存储在内存中,如果响应非常大,那岂不是会有问题?在我的测试中,似乎并不是存储在内存中。 它可能存储在非用户内存中,比如内核内存中吗?我对网络下载数据时内部工作原理不太熟悉。
请注意,我并不是在询问通过调用response.Content.ReadAsStringAsync()来消耗响应内容。我想知道的是,在我开始通过调用response.Content.ReadAsStringAsync()之类的方法来消耗响应之前,HttpClient是如何读取和存储响应的。

4
它不会将其存储在任何地方,除非您调用ReadAs...,服务器尚未发送响应。 - Charlieface
3
是的,它发送了请求,但实际上是否显示了响应中接收到的所有字节呢?无论如何,Fiddler是一个透明代理,很可能会完全缓存请求和响应以便解析它们。尝试使用Wireshark并观察实际的网络数据包,你会发现在调用ReadAsStream并实际从流中读取字节之前,响应流并没有完全被读取。 - Charlieface
从客户端-服务器通信的角度来看,我没有意识到客户端会让服务器等待返回数据。我以为一旦请求发出,服务器会持续返回数据而不需要等待客户端读取。我猜这可能与套接字的工作方式有关。 - JamesL
1
这就是TCP的工作原理,它在发送一定量的数据后等待ACK确认。不过,这个确认可能不仅仅是头部信息。 - Charlieface
1
这就是TCP的工作原理,它在发送一定量的数据后等待确认(ACK)。这个确认可能不仅仅是头部信息。 - undefined
显示剩余4条评论
1个回答

2

如果你使用ResponseHeadersRead,它就不会把数据存储在任何地方。在调用ReadAs...之前,服务器尚未完全发送响应。

关于在Fiddler中查看请求:是的,请求已发出,但它是否实际显示了接收到的所有字节?

无论如何,Fiddler是一个透明代理,可能会完全缓存请求和响应以进行解析。尝试使用Wireshark并观察实际的网络数据包,你会发现在调用ReadAsStream并从流中读取字节之前,响应流尚未完全读取。

这就是TCP的工作方式(HTTP运行在TCP套接字上):在一定量的数据之后,它等待一个ACK。它可能不仅仅是头部,因为TCP通常在等待ACK之前推送多个数据包。

如果你在足够长的时间内不读取数据,服务器将会断开连接。


如果我使用ResponseContentRead,这会被缓存在内存中吗? - Emil
1
是的,正确的,整个事情都被缓冲了。 - Charlieface

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接