底层连接已关闭:接收时发生了意外错误

46

我有如下代码:

private Uri currentUri;

private void Form1_Load(object sender, EventArgs e)
{
    currentUri = new Uri(@"http://www.stackoverflow.com");
    HttpWebRequest myRequest = (HttpWebRequest) HttpWebRequest.Create("http://www.stackoverflow.com");
    WebProxy myProxy = new WebProxy("120.198.230.8:81");
    myRequest.Proxy = myProxy;

    HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();

    webBrowser1.DocumentStream = myResponse.GetResponseStream();

    webBrowser1.Navigating += new WebBrowserNavigatingEventHandler(webBrowser1_Navigating);
}

void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
    if (e.Url.AbsolutePath != "blank")
    {
        currentUri = new Uri(currentUri, e.Url.AbsolutePath);
        HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(currentUri);

        HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();

        webBrowser1.DocumentStream = myResponse.GetResponseStream();
        e.Cancel = true;
    }
}

编译后:

错误:类型为“System.Net.WebException”的未经处理的异常发生在 System.dll 中

附加信息:基础连接被关闭:在接收时发生了意外错误。

位于行 HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();

请帮帮我。

9个回答

81

HttpWebRequest.KeepAlive 设置为 false 对我无效。

由于我正在访问 HTTPS 页面,因此我必须将服务点安全协议设置为 Tls12。

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

请注意,还有其他SecurityProtocolTypes: SecurityProtocolType.Ssl3SecurityProtocolType.TlsSecurityProtocolType.Tls11

所以如果Tls12对您不起作用,请尝试剩下的三个选项。

同时请注意,您可以设置多个协议。在大多数情况下,这是更可取的。

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

编辑:由于这是一个安全标准的选择,显然最好选择最新版本(截至撰写本文为TLS 1.2),而不仅仅是选择能够工作的版本。事实上,SSL3自2015年起已被正式禁止使用,而TLS 1.0和TLS 1.1也很快可能会被禁止使用。来源:@aske-b


5
尽管这是我们解决最近这个问题的一个方法,但我们的根本原因是服务器端的更改禁用了对TLS 1.0的支持。因此,根据您的具体情况可能会有多种解决方法。 - Sam Storie
很高兴知道。我在访问第三方服务器的数据时遇到了这个问题,所以我无法控制他们的TLS支持。 - Bartho Bernsmann
我应该把这个添加到哪里? - Moeez
@Faisal:在使用HttpWebRequest之前 - Bartho Bernsmann
当我从在线安装程序下载任何版本的SQL Server时,我遇到了同样的错误。原来我在注册表中禁用了TLS 1.0(客户端和服务器均为此,作为漏洞修复的一部分),导致发生问题。启用后并重新启动Windows,问题得到解决。谢谢。 - rvsingh42

28

底层连接被关闭:接收时发生了意外错误。

当服务器或其他网络设备意外关闭现有的传输控制协议(TCP)连接时,会出现此问题。当服务器或网络设备上的超时值设置过低时,可能会出现此问题。要解决此问题,请参见解决方法A、D、E、F和O。如果服务器意外重置连接,例如由于未处理的异常导致服务器进程崩溃,则也可能会出现此问题。分析服务器日志以查看是否存在此问题。

解决方法

为了解决此问题,请确保使用最新版本的.NET Framework。

向类中添加一个方法来覆盖GetWebRequest方法。这个更改可以让您访问HttpWebRequest对象。如果您正在使用Microsoft Visual C#,则新方法必须类似于以下内容。

class MyTestService:TestService.TestService
{
    protected override WebRequest GetWebRequest(Uri uri)
    {
        HttpWebRequest webRequest = (HttpWebRequest) base.GetWebRequest(uri);
        //Setting KeepAlive to false
        webRequest.KeepAlive = false;
        return webRequest;
    }
}

来自KB915599的摘录:当您尝试在基于.NET Framework 1.1 Service Pack 1构建的应用程序中进行HTTP请求时,可能会收到一个或多个错误消息。


@Raji 在调用 HttpWebRequest 之前,你必须先编写这个。 - Nagaraj S
@Nagaraj,你能告诉我在下面提到的网址中代码缺少了什么吗?https://stackoverflow.com/questions/49978481/when-uploading-file-in-ftp-got-error-the-underlying-connection-was-closed-an?noredirect=1#comment86974929_49978481 - Raji
2
以上的 KB 摘录是一个指向不存在网页的链接。 - Su Llewellyn

7
  • .NET 4.6及以上版本可以默认支持TLS 1.2,无需额外操作。
  • .NET 4.5. TLS 1.2被支持,但不是默认协议。您需要选择使用它。在连接到受保护资源之前,请确保执行以下代码以使TLS 1.2成为默认值:
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

  • .NET 4.0. 不支持TLS 1.2,但如果系统中已安装.NET 4.5(或更高版本),即使应用程序框架不支持它,仍然可以选择使用TLS 1.2。唯一的问题是,.NET 4.0中的SecurityProtocolType没有TLS1.2的条目,因此我们必须使用此枚举值的数字表示:
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

  • .NET 3.5或更低版本不支持TLS 1.2。请升级应用程序到较新版本的框架。


1
上面的内容并不完全适用于旧版 .Net,对于旧版本,您可以手动设置 TLS。ServicePointManager.SecurityProtocol = (System.Net.SecurityProtocolType) 3072; // 也称为 Tls12 - phanf
你提到了“默认”协议版本。这是否意味着ServicePointManager中的全局设置可以在特定使用(例如HttpWebRequest)时被覆盖? - Anton Shepelev

1

对我来说,市面上的解决方案都没有起作用。我最终发现了以下组合:

  • 客户端系统:Windows XP Pro SP3
  • 客户端系统已安装 .NET Framework 2 SP1、3、3.5
  • 使用经典 Web 服务 (.asmx) 目标为 .NET 2 的软件
  • 服务器:IIS6
  • 网站“安全通信”设置为:
    • 需要安全通道
    • 接受客户端证书

enter image description here

显然,正是最后一个选项导致了问题。我通过尝试在Internet Explorer中直接打开Web服务URL来发现这一点。它一直无限期地挂起,试图加载页面。禁用“接受客户端证书”允许页面正常加载。我不确定这是否是该特定系统的问题(可能是故障的客户端证书?)由于我没有使用客户端证书,因此这个选项对我有效。


1

我的托管服务器阻止请求URL,代码网站出现相同的错误 无法从传输连接中读取数据: 远程主机强制关闭了现有的连接。 ---> System.Net.Sockets.SocketException: 远程主机强制关闭了现有的连接

enter image description here

经过很长时间的努力,采取以下步骤解决了这个问题:

  1. 在调用 Web URL 之前添加以下代码:

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

  2. 如果问题仍未解决,则将 .net 版本升级到 4.7.2,但我认为这是可选的。

  3. 最后,我检查了托管服务器的安全级别,发现 TLS 握手使用了“https://www.ssllabs.com/ssltest/index.html”网站来进行测试,并检查了请求 URL 的安全级别。然后我发现,请求 URL 必须启用弱级密码套件,您可以在下面的图片中看到。

enter image description here

现在这里是我的托管服务器支持的密码套件。

enter image description here

如果您可以控制请求URL主机服务器,则可以同步这两个服务器的密码套件。但在我的情况下,这是不可能的,因此我在我的托管服务器上应用了以下脚本以启用所需的弱级别密码套件。

Enable-TlsCipherSuite -Name "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"
Enable-TlsCipherSuite -Name "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
Enable-TlsCipherSuite -Name "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
Enable-TlsCipherSuite -Name "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
Enable-TlsCipherSuite -Name "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"
Enable-TlsCipherSuite -Name "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"
Enable-TlsCipherSuite -Name "TLS_RSA_WITH_AES_256_GCM_SHA384"
Enable-TlsCipherSuite -Name "TLS_RSA_WITH_AES_128_GCM_SHA256"
Enable-TlsCipherSuite -Name "TLS_RSA_WITH_AES_256_CBC_SHA256"
Enable-TlsCipherSuite -Name "TLS_RSA_WITH_AES_128_CBC_SHA256"
Enable-TlsCipherSuite -Name "TLS_RSA_WITH_AES_256_CBC_SHA"
Enable-TlsCipherSuite -Name "TLS_RSA_WITH_AES_256_CBC_SHA"

将 TlsCipherSuite 启用为指定名称的加密套件。

应用上述脚本后,我的托管服务器的加密套件级别如下:

enter image description here

然后我的问题得到了解决。

备注:降低服务器安全级别不是推荐的选项。


1

我在使用PowerShell脚本块时遇到了相同的异常:“调用“ExecuteQuery”时出错,参数为“0”:底层连接已关闭:接收时发生意外错误。

 #Setup Credentials to connect
        $Username="user@domain.com"  
        $Password="pwd4user"
        $securePassword = ConvertTo-SecureString $Password -AsPlainText -Force
        #$Cred = Get-Credential
        $Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, $securePassword)
     
        #Setup the context
        $Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
        $Ctx.Credentials = $Cred
 
        #Get the Library and Its Root Folder
        $Library=$Ctx.web.Lists.GetByTitle($LibraryName)
        $Ctx.Load($Library)
        $Ctx.Load($Library.RootFolder)
        $Ctx.ExecuteQuery()` 

上述代码块可以在我的一台电脑上运行,但在另一台电脑上却不能。我在头部添加了这行代码[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12,但再次运行时,我得到了另一个异常:“Exception calling "ExecuteQuery” with "0" argument(s): "The partner returned a bad sign-in name or password error. For more information, see Federation Error-handling Scenarios."”,我可以确认我的凭据没有问题,因为它可以在一台电脑上工作。然后我搜索了异常信息,得到了这个网址:The partner returned a bad sign-in name or password error. For more information, see Federation Error-handling Scenarios.

该网站发现代理可能会导致此异常,然后我注意到这两台电脑上的代理不同,所以我更改了脚本无法工作的电脑上的代理。最终所有异常都消失了。


0
在执行查询之前,我将语句放置如下,并解决了我的错误。只是提供给你参考,如果有助于别人的话。
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; ctx.ExecuteQuery();

因为这是Bartho Bernsmann的优秀答案的重复,所以被踩了。 - Anton Shepelev
因为这个答案不是重复的,而是适用于旧版本的 .Net 的相关答案,所以我点了赞。 - Jay13

0
为了进一步阐述Bartho Bernsmann的答案,我想补充一点,即可以通过稍加思考来实现通用、未来可扩展的实现。
static void AllowAllSecurityPrototols()
{   int                  i, n;
    Array                types;
    SecurityProtocolType combined;

    types = Enum.GetValues( typeof( SecurityProtocolType ) ); 
    combined = ( SecurityProtocolType )types.GetValue( 0 );

    n = types.Length;
    for( i = 1; i < n; i += 1 )
    {   combined |= ( SecurityProtocolType )types.GetValue( i );  }

    ServicePointManager.SecurityProtocol = combined;
}

我在访问互联网的类的静态构造函数中调用此方法。

-1
我也在进行网络爬虫项目,遇到了同样的问题,应用了下面的代码后,它很好地解决了。如果你不了解 TLS 版本,则可以应用以下所有内容,否则可以应用特定的版本。
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;

因为这是Bartho Bernsmann的优秀答案的重复,所以被踩了。 - Anton Shepelev
我刚刚分享了我遇到的实时问题,并以同样的方式得到了解决方案 :) - Anjan Kant
但是你看到另一个答案已经给出了相同的解决方案了吗?如果是这样,为什么还要发帖呢? - Anton Shepelev

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