gpt4 book ai didi

c# - 为什么 HttpWebRequest.GetRequestStream() 尝试连接

转载 作者:行者123 更新时间:2023-11-30 12:40:34 24 4
gpt4 key购买 nike

也许这似乎是一个奇怪的问题,但我遇到了以下情况:

我尝试向服务发出发布请求,并添加我选择的发布数据,从请求中创建一个 Stream 并使用 StreamWriter 在其上写入正文。

但是,在我实际执行请求(使用 GetResponse)之前,甚至在我写入流对象之前,我就得到了一个“无法连接异常”

var stream = request.GetRequestStream();

经过一番调查,我意识到 request.GetRequestStream() 实际上是在尝试连接 .我的问题是 与服务器的网络连接 (防火墙问题)。

但我的问题是 为什么 HttpWebRequest.GetRequestStream() 尝试连接 ???

我的简单想法是,在创建请求时,与请求的服务器没有连接。

我发现了一些相关的问题,例如 this

但它似乎并没有完全回答我的问题。

请问有什么解释吗?

PS:任何关于如何避免这种“早期”连接效应的建议将不胜感激。

最佳答案

.NET I/O API 通常在 streams 上运行,它们是允许开发人员读取和写入有序数据序列的 API。通过对通用 API 进行读写,它使通用库能够对流进行操作以执行强大的操作:压缩、加密、编码等(顺便说一句,类似地处理不同类型的 I/O 历史悠久,最著名的是在 UNIX其中everything is a file。)

尽管在许多不同类型的流中读取和写入数据的工作方式非常相似,但打开一个流要通用得多。考虑一下用于打开文件、发出 HTTP 请求和执行数据库查询的截然不同的 API。

因此,.NET 的 Stream 类没有泛型 Open()方法,因为在不同类型的流之间使流进入打开状态是非常不同的。相反,流 API 期望得到一个已经打开的流,其中“打开”意味着它已准备好被写入和/或读取。

因此,在 .NET 中有一个典型的 I/O 模式:

  • 编写一些特定于资源的代码来打开一个流。这些 API 通常返回一个开放流。
  • 将该开放流移交给从中读取和/或写入的通用 API。
  • 完成后关闭流(也是通用的)。

  • 现在想想上面的模式如何与 HTTP 请求对齐,它有以下步骤:
  • 一个。在 DNS
  • 中查找服务器的 IP 地址
  • 湾。与服务器建立 TCP 连接
  • C。将 URL 和请求头发送到服务器
  • d。如果是 POST(或 PUT 或其他发送请求正文的方法),则上传请求正文。如果它是 GET,则这是一个无操作。
  • e.现在阅读回复
  • F。最后,关闭连接。

  • (我在上面的步骤中忽略了很多现实世界的复杂性,如 SSL、保持事件连接、缓存响应等,但基本工作流程足够准确,可以回答您的问题。)

    好的,现在让自己置身于 .NET 团队尝试构建 HTTP 客户端 API,记住将非通用部分(“获取开放流”)与通用部分分开:读取和/或写入,然后关闭流。

    如果您的 API 只需处理 GET 请求,那么您可能会在执行返回响应流的相同 API 时建立连接。这正是 HttpWebRequest.GetResponse 做。

    但如果您发送 POST 请求(或 PUT 或其他类似方法),则必须将数据上传到服务器。与只有几 KB 的 HTTP header 不同,您在 POST 中上传的数据可能很大。如果您要上传 10GB 的文件,您不希望在上传到服务器所需的时间将其停放在 RAM 中。这会同时扼杀您客户的表现。相反,您需要一种方法来获得 Stream因此,您只需在发送到服务器之前将小 block 数据加载到 RAM 中。请记住 Stream没有 Open()方法,因此您的 API 必须提供开放流。

    现在您有了第一个问题的答案: HttpWebRequest.GetRequestStream 必须建立网络连接,因为如果没有,那么流将被关闭并且您无法写入它。

    现在开始你的第二个问题:你怎么能延迟连接?我假设您的意思是连接应该发生在第一次写入请求流时。一种方法是编写一个继承自 Stream 的类。只调用 GetRequestStream尽可能晚,然后将所有方法委托(delegate)给底层请求流。像这样作为起点:
    using System.Net;
    using System.Threading.Tasks;
    using System.Threading;

    class DelayConnectRequestStream : Stream
    {
    private HttpWebRequest _req;
    private Stream _stream = null;

    public DelayConnectRequestStream (HttpWebRequest req)
    {
    _req = req;
    }

    public void Write (byte[] buffer, int offset, int count)
    {
    if (_stream == null)
    {
    _stream = req.GetRequestStream();
    }
    return _stream.Write(buffer, offset, count);
    }

    public override WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
    {
    if (_stream == null)
    {
    // TODO: figure out if/how to make this async
    _stream = req.GetRequestStream();
    }
    return _stream.WriteAsync(buffer, offset, count, cancellationToken);
    }

    // repeat the pattern above for all needed methods on Stream
    // you may need to decide by trial and error which properties and methods
    // must require an open stream. Some properties/methods you can probably just return
    // without opening the stream, e.g. CanRead which will always be false so no need to
    // create a stream before returning from that getter.

    // Also, the code sample above is not thread safe. For
    // thread safety, you could use Lazy<T> or roll your own locking.
    }

    但老实说,上面的方法似乎有点矫枉过正。如果我站在你的立场上,我会看看为什么我要推迟开放流,看看是否有其他方法可以解决这个问题。

    关于c# - 为什么 HttpWebRequest.GetRequestStream() 尝试连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41425966/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com