如何使用HttpWebRequest连接但等待发送任何标头

本文关键字:任何标 等待 何使用 HttpWebRequest 连接 | 更新日期: 2023-09-27 18:00:28

我想发出https请求,但我想先启动连接,而不发送头,甚至不发送GET /something/ HTTP/1.1部分。换句话说,我想保持连接准备就绪,并在完成后尽快发送所有内容。

我本可以使用一个简单的TCP/IP来完成这项工作,但目前我遇到了一些问题。

我已经尝试过SendChunked属性,但它只发送要发布的部分分块数据。

编辑:为了更清楚,我想要的是:

  • 连接到IP
  • 创建SSL流和AuthenticateAsClient
  • 等待信号
  • 现在发送web请求

我已经练习了等待部分,所以没有必要对此进行详细解释。

如何使用HttpWebRequest连接但等待发送任何标头

简短回答

HttpWebRequest不公开任何接口,以允许在发出请求之前预先预热连接。

动机

有人想要这样做的原因是,打开TCP连接需要启动器在发送任何数据之前等待一个RTT,并且HTTPS可能需要另一个RTT来执行密钥交换。

如果从客户端到数据中心的RTT为50毫秒,那么像这样预热连接可以将发送简单请求所需的时间从125毫秒(2.5个RTT用于发送请求,但未获得响应)降低到25毫秒(0.5个RTT,用于发送请求但未获得应应应)。这减少了80%。

替代解决方案

在不编写自己的Http客户端或使用HttpWebRequest以外的东西的情况下,可以实现一些减少,但在某些情况下,它将不得不等待。

一般的技术是依靠HTTP1.1重新恢复连接(也称为保持活动)来通过现有的TCP套接字/SSL会话发送请求。

先决条件:您需要知道您正在调用的web服务器的保持活动间隔。60秒是非常典型的,但不要想当然,用Fiddler观察它,或者检查服务器和负载均衡器上的设置(如果你可以访问它们)。

假设保活时间间隔为60秒。创建一个HttpWebRequest并将一个请求发送到"ping"url(即使是不存在的文件……除非服务器配置错误,否则404响应时连接仍不应关闭)。在小于保持活动间隔的某个间隔(例如,每55秒),再次重新发送请求。当您想向服务器发送请求时,您需要等待锁定您拥有的单个HttpWebRequest。当锁在没有等待的情况下可用时,您的请求通常会立即通过现有的TCP套接字和SSL会话。在HttpWebRequest被锁定的罕见情况下,您将不得不等待多达1个RTT才能释放它(当它被锁定时,平均需要等待0.5个RTT,这是罕见的,因为很可能请求已经在网上发送,响应也可能已经在网上)。

这个解决方案不能保证套接字将保持活动,但它会很好地工作。

不必嗤之以鼻,但如果性能如此关键,您可能不应该使用HTTP和/或担心编写或使用非HttpWebRequest客户端。

我看了你的另一篇关于WebClient和TcpClient之间性能的文章。我想确保我对这篇文章的回答和你们在另一篇文章中所做的一致。我想给出的答案是使用TcpClient,但在你的另一篇文章中,你发现这很慢。我编了同样的测试,但结果不同。在我的测试中,TcpClient平均比WebClient快10ms。

使用WebClient

Stopwatch sw = new Stopwatch();
sw.Start();
using (WebClient client = new WebClient())
{
    string response = client.DownloadString("https://www.google.com");
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

使用TcpClient

Stopwatch sw = new Stopwatch();
sw.Start();
using (TcpClient client = new TcpClient("www.google.com", 443))
using (SslStream stream = new SslStream(client.GetStream(), true))
{
    stream.AuthenticateAsClient("www.google.com");
    using (StreamWriter writer = new StreamWriter(stream))
    using (StreamReader reader = new StreamReader(stream))
    {
        writer.AutoFlush = true;
        // Wait for your signal here

        writer.Write("GET /'r'n");
        string response = reader.ReadToEnd();
    }
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

你需要使用TcpClient类来完成你想要做的事情。HttpWebRequest没有提供对底层流和连接所需的级别访问。

使用TcpClient,您可以在发送"GET/"之前等待信号。