【问题标题】:Unable to read data from the transport connection : An existing connection was forcibly closed by the remote host无法从传输连接读取数据:现有连接被远程主机强行关闭
【发布时间】:2011-07-22 04:42:33
【问题描述】:

我有一个服务器应用程序,有时,当客户端尝试连接时,我收到以下错误:

注意:“无法从客户端获取流或登录失败”是我在 catch 语句中添加的文本

它停止的那一行(sThread:第 96 行)是:

tcpClient = (TcpClient)client;
clientStream = tcpClient.GetStream();
sr = new StreamReader(clientStream);
sw = new StreamWriter(clientStream);

// line 96:                 
a = sr.ReadLine();

什么可能导致这个问题?请注意,它不会一直发生

【问题讨论】:

  • 所有这意味着您可以将您的框架升级到类似 4.7.2 的版本,它可能会在没有任何进一步问题的情况下工作。它对我有用。它升级了用于传输级通信的安全协议。

标签: c# .net ioexception


【解决方案1】:

我在调用网络服务时收到此错误。该问题还与传输级别的安全性有关。我可以通过网站项目调用 Web 服务,但是在测试项目中重用相同的代码时,我会得到一个包含此消息的 WebException。在拨打电话之前添加以下行解决了问题:

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

编辑

System.Net.ServicePointManager.SecurityProtocol - 此属性 选择安全套接字层 (SSL) 或传输的版本 用于新连接的层安全 (TLS) 协议 仅安全超文本传输​​协议 (HTTPS) 方案;现存的 连接没有改变。

我相信SecurityProtocol 配置在选择协议版本时在 TLS 握手期间很重要。

TLS handshake - 该协议用于交换双方通过 TLS 交换实际应用数据所需的所有信息。

ClientHello - 客户端发送 ClientHello 消息,指定它支持的最高 TLS 协议版本...

ServerHello - 服务器以 ServerHello 消息进行响应,其中包含所选的协议版本...所选的协议版本应该是客户端和服务器都支持的最高版本。例如,如果客户端支持 TLS 1.1 版本,服务器支持 1.2 版本,则应选择 1.1 版本;不应该选择 1.2 版。

【讨论】:

  • 这救了我!谢啦。在我的调试器中,我试图在测试时调用 https 服务并且遇到了 OP 遇到的问题。
  • 我们是否更了解它的工作原理/原因?我一直在为 PostAsync 调用而苦苦挣扎,这似乎也解决了我的错误。很高兴它起作用了,但我也想知道为什么。
  • @HansVonn 谢谢!为我节省了大量时间 - 关于它的工作原理它只是限制了您在连接时使用的 TLS 版本。
  • 不敢相信这让我又一次了!谢谢
  • 谢谢!这让我发疯了。
【解决方案2】:

此错误通常表示目标计算机正在运行,但您尝试连接的服务不可用。 (它要么停止,要么崩溃,要么正忙于另一个请求。)

英文: 与机器(运行服务的远程主机/服务器/PC)的连接已建立,但由于该服务在该机器上不可用,因此该机器没有知道如何处理请求。

如果与机器的连接不可用,您会看到不同的错误。我忘记了它是什么,但它类似于“服务无法访问”或“不可用”。

编辑 - 添加

这可能是由防火墙阻止端口引起的,但鉴于您说它是间歇性的(“有时当客户端尝试连接时”),这不太可能。本来我没写,是因为回复之前心理已经排除了。

【讨论】:

  • 问题是,当我启动服务器时,有大约 50 个客户端连接到我的服务器。我在接受客户端时实现了一种等待信号..类似于 while (Program.waitToFinishLoginAtClient == true && ajutor
  • 这个“等待”会是问题吗?
  • 我应该顺其自然吗?等不及了?
  • 我认为等待是问题所在。我对您的代码知之甚少,无法确定,但这听起来很可能。只是好奇您是否以“艰难的方式”构建了自己的服务,或者您是否正在使用 WCF 甚至远程处理……
  • 基于这里的一小段代码,在我看来,如果它在每个连接的单独线程内,则可以避免“等待”问题。以防万一猜对了,这里有一个多线程 TCP 服务的例子,它可以帮助你:switchonthecode.com/tutorials/…
【解决方案3】:

我的具体情况是 Azure 应用服务的最低 TLS 版本更改为 1.2

我不知道这是否是从现在开始的默认设置,但将其改回 1.0 即可。

您可以访问“SSL 设置”中的设置。

【讨论】:

  • 天哪,非常感谢!我已经坚持了很长时间,我检查了 Web 应用程序的 SSL 设置,最小值设置为 1.2 而不是 1.0。当我将它改回 1.0 并重新启动网络应用程序时,它工作了!非常感谢!
  • 非常感谢@hugo-hilário,令人惊讶的是它也对我有用!你到底是怎么找到这么棘手的解决方案的! :D
  • @hosjay 这对我来说也是地狱 :)
  • 救了我的好朋友!
  • 我的 Azure Function v2 遇到了这个问题
【解决方案4】:

根据“Hans Vonn”的回复。

在拨打电话之前添加以下行解决了问题:

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

在添加安全协议并且工作正常之后,但我必须在每个不健康的 API 调用之前添加。我只是将 .net 框架版本至少升级到 4.6 并且按预期工作不需要在每次 API 调用之前添加。

【讨论】:

  • 非常感谢。你让我今天一整天都感觉很好。如果我提到在此之前我还测试了停用防火墙并添加了 ServicePointManager.ServerCertificateValidationCallback 但不起作用,这可能对某些人有用。
  • 请记住,这必须在您创建请求之前进行。归功于 - stackoverflow.com/a/57377861/1572632
【解决方案5】:

不确定这些博客文章中的哪些修复有帮助,但其中一个为我解决了这个问题...

http://briancaos.wordpress.com/2012/07/06/unable-to-read-data-from-the-transport-connection-the-connection-was-closed/

帮助我的诀窍是退出使用 WebRequest 并改用 HttpWebRequest。 HttpWebRequest 允许我使用 3 个重要设置:

http://briancaos.wordpress.com/2012/06/15/an-existing-connection-was-forcibly-closed-by-the-remote-host/

  • 第 1 步:禁用 KeepAlive
  • 第 2 步:将 ProtocolVersion 设置为 Version10
  • 第 3 步:限制服务点的数量

【讨论】:

  • 这个答案为我解决了同样的问题。我在 IIS7 的 Http Response Headers 部分中关闭了“Keep Alive”
  • 我应该补充一点,我还必须将此代码添加到具有该行为的 Web 服务的 Reference.cs 中。受保护的覆盖 System.Net.WebRequest GetWebRequest(Uri uri) { System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)base.GetWebRequest(uri); webRequest.KeepAlive = false;返回网络请求; }
【解决方案6】:

从我们的一台服务器调用 HTTPS 服务也引发了“无法从传输连接读取数据:现有连接被强制关闭”异常。但是,HTTP 服务运行良好。使用 Wireshark 发现是 TLS 握手失败。最终是需要更新服务器上的密码套件。

【讨论】:

  • 这就是发生在我身上的事情。 A 向 SSL 连接发送了过期的证书。 A 更新证书并工作。
【解决方案7】:

对于以后可能会发现这个问题的人,在 .NET 4.6 版之后,我也遇到了这个问题。

确保检查 web.config 文件中的以下行:

<compilation debug="true" targetFramework="4.5">
...
<httpRuntime targetFramework="4.5" />

如果您在服务器上运行 4.6.x 或更高版本的 .NET,请确保调整这些 targetFramework 值以匹配服务器上框架的版本。如果您的版本低于 4.6.x,那么我建议您升级 .NET 并使用新版本,除非您的代码依赖于旧版本(在这种情况下,您应该考虑更新它)。

我把targetFrameworks改成4.7.2,问题就消失了:

<compilation debug="true" targetFramework="4.7.2">
...
<httpRuntime targetFramework="4.7.2" />

较新的框架通过使用可用的最佳协议并阻止不安全或过时的协议来解决此问题。如果您尝试连接或调用的远程服务出现此错误,则可能是它们不再支持旧协议。

【讨论】:

  • 没错!框架 4.6.2 有错误!我将框架降级为 .NET 4.0(因为我没有 4.7. 及更高版本),它又可以工作了!典型的微软故障。
  • 必须将 httpRuntime 目标框架设置为 4.6.2 以匹配我的编译目标框架。
  • 我必须将 targetFramework 设置为 4.8,一旦我这样做了,这个问题就消失了!谢谢!
  • 这是我的问题。谢谢!
  • 这是经过 2 小时的故障排除后的结果。有人从未更新过 httpRuntime 道具
【解决方案8】:

这对间歇性问题没有帮助,但可能对其他有类似问题的人有用。

我克隆了一个虚拟机并在另一个网络上使用新的 IP 地址启动它,但没有更改 IIS 中的绑定。 Fiddler 向我显示“无法从传输连接读取数据:现有连接被远程主机强行关闭”,IE 告诉我“在高级设置中打开 TLS 1.0、TLS 1.1 和 TLS 1.2”。将绑定更改为新的 IP 地址为我解决了这个问题。

【讨论】:

    【解决方案9】:

    由于某种原因,与服务器的连接丢失。可能是服务器显式关闭了连接,或者服务器上的错误导致它意外关闭。或者客户端和服务器(交换机或路由器)之间的某些东西断开了连接。

    可能是服务器代码导致了问题,也可能不是。如果您有权访问服务器代码,则可以在其中进行一些调试以告诉您何时关闭客户端连接。这可能会为您提供一些关于何时以及为何断开连接的指示。

    在客户端,您必须编写代码以考虑服务器随时出现故障的可能性。事实就是这样:网络连接本质上是不可靠的。

    【讨论】:

      【解决方案10】:

      这解决了我的问题。我在发出请求之前添加了这一行:

      System.Net.ServicePointManager.Expect100Continue = false;
      

      似乎服务器中存在不支持 100-continue 行为的代理。

      【讨论】:

        【解决方案11】:

        有点死灵,但我需要添加一个答案。 webrequest 用户代理默认为空。只需谷歌“阻止空用户代理”,您就会发现许多网络服务器管理员强烈希望这样做。 发送我的请求 request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0"; 解决了这个问题。

        【讨论】:

          【解决方案12】:
          • 我从 Console App 发送 HttpWebRequest,而 UserAgent 是 null by(默认),所以设置 UserAgent 与设置一起工作 安全协议。
          • 应在创建 HttpWebRequest 之前设置 SecurityProtocol。

          ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
          
          HttpWebRequest req = (HttpWebRequest)WebRequest.Create("yourpostURL");
          req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36";
          

          【讨论】:

            【解决方案13】:

            我过去遇到过这个问题。我正在使用 PostgreSQL,当我运行我的程序时,有时它会连接,有时它会抛出类似的错误。

            当我试验我的代码时,我将我的连接代码放在公共表单下方的第一行。这是一个例子:

            之前:

                public Form1()
                    {
                    //HERE LIES SOME CODES FOR RESIZING MY CONTROLS DURING RUNTIME
                    //CODE
                    //CODE AGAIN
                    //ANOTHER CODE
                    //CODE NA NAMAN
                    //CODE PA RIN!
            
            
            
            
            
                    //Connect to Database to generate auto number
                    NpgsqlConnection iConnect = new NpgsqlConnection("Server=localhost;Port=5432;User ID=postgres;Password=pass;Database=DB");
                    iConnect.Open();
                    NpgsqlCommand iQuery = new NpgsqlCommand("Select * from table1", iConnect);
                    NpgsqlDataReader iRead = iQuery.ExecuteReader();
                    NpgsqlDataAdapter iAdapter = new NpgsqlDataAdapter(iQuery);
            
                    DataSet iDataSet = new DataSet();
                    iAdapter.Fill(iDataSet, "ID");
            
                    MessageBox.Show(iDataSet.Tables["ID"].Rows.Count.ToString());
                    }
            

            现在:

                public Form1()
                    {
                    //Connect to Database to generate auto number
                    NpgsqlConnection iConnect = new NpgsqlConnection("Server=localhost;Port=5432;User ID=postgres;Password=pass;Database=DB");
                    iConnect.Open();
                    NpgsqlCommand iQuery = new NpgsqlCommand("Select * from table1", iConnect);
                    NpgsqlDataReader iRead = iQuery.ExecuteReader();
                    NpgsqlDataAdapter iAdapter = new NpgsqlDataAdapter(iQuery);
            
                    DataSet iDataSet = new DataSet();
                    iAdapter.Fill(iDataSet, "ID");
            
                    MessageBox.Show(iDataSet.Tables["ID"].Rows.Count.ToString());
            
            
            
            
            
                    //HERE LIES SOME CODES FOR RESIZING MY CONTROLS DURING RUNTIME
                    //CODE
                    //CODE AGAIN
                    //ANOTHER CODE
                    //CODE NA NAMAN
                    //CODE PA RIN!
            
                    }
            

            我认为程序在做任何事情之前必须先读取连接,我不知道,如果我错了,请纠正我。但根据我的研究,这不是代码问题——实际上是机器本身造成的。

            编码愉快!

            【讨论】:

              【解决方案14】:
              System.Net.ServicePointManager.Expect100Continue = false;
              

              此问题有时是由于在 Web 服务器上实现了代理服务器的原因。通过在调用发送服务之前放置此行来绕过代理服务器。

              【讨论】:

                【解决方案15】:

                对我来说,在 IIS 绑定中它具有 Web 服务器的 IP 地址是一个问题。 我将其更改为使用所有未分配的 IP,然后我的应用程序开始工作。

                【讨论】:

                  【解决方案16】:

                  python clr 使用 adomd 对 Microsoft 分析服务运行 mdx 查询时遇到错误

                  我在 Hans Vonn 的帮助下解决了这个问题,这是 python 版本:

                  clr.AddReference("System.Net")
                  from System.Net import ServicePointManager, SecurityProtocolType 
                  ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls
                  

                  【讨论】:

                    【解决方案17】:

                    我运行了一个第三方应用程序 (Fiddler) 来尝试查看正在发送的请求。关闭此应用程序为我修复了它

                    【讨论】:

                      【解决方案18】:

                      我们遇到了一个非常相似的问题,客户的网站试图连接到我们的 Web API 服务并获得相同的消息。当运行 IIS 的服务器上没有代码更改或 Windows 更新时,这种情况开始完全出乎意料地发生。

                      在我们的案例中,结果表明调用网站使用的 .Net 版本仅支持 TLS 1.0,并且由于某种原因,我们运行 IIS 的服务器停止了似乎已停止接受 TLS 1.0 调用。为了诊断我们必须通过 IIS 服务器上的注册表显式启用 TLS,然后重新启动该服务器。这些是注册键:

                      [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
                          1.0\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001
                      
                          [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
                          1.0\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001
                      
                          [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
                          1.1\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001
                      
                          [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
                          1.1\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001
                      
                          [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
                          1.2\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001
                      
                          [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
                          1.2\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001
                      
                      If that doesn't do it, you could also experiment with adding the entry for SSL 2.0:
                      
                      
                          [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client]
                          "DisabledByDefault"=dword:00000000
                          "Enabled"=dword:00000001
                      
                          [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server]
                          "DisabledByDefault"=dword:00000000
                          "Enabled"=dword:00000001
                      

                      我对 another question here 的回答有这个我们用来添加条目的 powershell 脚本:

                      注意:启用旧的安全协议不是一个好主意,在我们的案例中,正确的答案是让客户端网站更新其代码以使用 TLS 1.2,但上面的注册表项可以提供帮助首先诊断问题。

                      【讨论】:

                        【解决方案19】:

                        发生这种情况的原因是我的 DI 提供程序存在递归依赖关系。就我而言,我有:

                        services.AddScoped(provider => new CfDbContext(builder.Options));
                        services.AddScoped(provider => provider.GetService<CfDbContext>());
                        

                        修复只是删除第二个作用域服务注册

                        services.AddScoped(provider => new CfDbContext(builder.Options));
                        

                        【讨论】:

                          【解决方案20】:

                          如果您在域上有 https 证书,请确保您在 IIS 中具有与域名的 https 绑定。 在 IIS -> 选择您的域 -> 单击绑定 站点绑定窗口打开。为 https 添加绑定。

                          【讨论】:

                            【解决方案21】:

                            遇到了类似的问题,并且根据我使用的应用程序以及我们是否绕过防火墙/负载平衡器而收到以下错误:

                            与 [blah] 的 HTTPS 握手(对于 #136)失败。 System.IO.IOException 无法从传输中读取数据 连接:已存在的连接被远程强行关闭 主机

                            ReadResponse() 失败:服务器没有为此请求返回完整的响应。服务器返回 0 个字节。

                            问题原来是 SSL 服务器证书丢失并且没有安装在几个服务器上。

                            【讨论】:

                              【解决方案22】:

                              首先尝试检查是否可以建立握手。我之前在上传文件时遇到过这个问题,当我删除上传并检查它是否可以在给定参数的情况下登录时,我才发现问题是路由不存在。

                              【讨论】:

                                【解决方案23】:

                                另一种选择是检查使用 try-catch 块生成的错误代码并首先捕获 WebException。

                                在我的情况下,由于 HTTPS url 上的证书问题,错误代码是“SendFailure”,一旦我点击 HTTP,问题就得到了解决。

                                https://docs.microsoft.com/en-us/dotnet/api/system.net.webexceptionstatus?redirectedfrom=MSDN&view=netframework-4.8

                                【讨论】:

                                  【解决方案24】:

                                  当代理服务器中的服务不可用时会出现此问题。我们可以绕过代理服务器。 在启动服务之前,应用此代码行。

                                  System.Net.ServicePointManager.Expect100Continue = false;
                                  

                                  Further details

                                  【讨论】:

                                    【解决方案25】:

                                    我收到此错误只是因为我试图与仅 https 的服务器建立 http 连接。将 URI 中的请求协议从 http 更改为 https 从而解决它。

                                    【讨论】:

                                      【解决方案26】:

                                      这就是我解决问题的方法:

                                                      int i = 0;
                                                      while (stream.DataAvailable == true)
                                                      {
                                                          bytes[i] = ((byte)stream.ReadByte());
                                                          i++;
                                                      }
                                      
                                                      data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                                                      Console.WriteLine("Received: {0}", data);
                                      

                                      【讨论】:

                                      • 这段代码有多余的布尔检查。 while (stream.DataAvailable == true) 你只需要下面的代码。检查某事是否为真以使其为真只是多余的。 while (stream.DataAvailable)
                                      猜你喜欢
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 2014-11-19
                                      • 2018-02-15
                                      • 2015-01-14
                                      相关资源
                                      最近更新 更多