无法从传输连接读取数据: 现有连接被远程主机强制关闭

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

enter image description here

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

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

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


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

是什么原因导致了这个问题? 请注意,这种情况并不总是发生

610736 次浏览

此错误通常意味着目标计算机正在运行,但您试图连接到的服务不可用。(它要么停止、崩溃,要么忙于处理另一个请求。)

英语: 与 机器(服务运行在的远程主机/服务器/PC)的连接已经建立,但是由于该服务不可用于该机器的 开始,该机器不知道如何处理请求。

如果到机器的连接不可用,您将看到一个不同的错误。我忘了它是什么,但它是沿着“服务无法到达”或“无法使用”的路线。

编辑添加

这可能是由于防火墙阻塞了端口造成的,但考虑到你说它是间歇性的(“有时当客户端试图连接”) ,这是非常不可能的。我最初没有包括这一点,因为在回答之前我在心里已经排除了这一点。

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

可能是服务器代码导致了问题,也可能不是。如果您可以访问服务器代码,可以在其中进行一些调试,以告诉您客户端连接何时关闭。这可能会给你一些关于什么时候以及为什么连接被丢弃的指示。

在客户机上,必须编写代码以考虑服务器在任何时候发生故障的可能性。事实就是这样: 网络连接本身就是不可靠的。

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

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/

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

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

从我们的一台服务器调用 HTTPS 服务也会抛出“ 无法从传输连接读取数据: 现有连接被强制关闭”异常。不过,HTTP 服务工作得很好。使用 WireSharkto 查看它是一个 TLS 握手失败。结果是服务器上的密码套件需要更新。

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

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

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

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

剪辑

System.Net.ServicePointManager.SecurityProtocol -此属性 选择传输层安全(SSL)或传输的版本 层安全(TLS)协议用于使用 安全超文本传输协议(HTTPS)计划; 连接不会改变。

我相信在选择协议版本时,在 TLS 握手过程中 SecurityProtocol配置非常重要。

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

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

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

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

当我试验我的代码时,我将我的 Connection 代码放在 public Form 下面的第一行。这里有一个例子:

之前:

    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!


}

我认为程序必须首先读取连接,然后再做任何事情,我不知道,如果我错了就纠正我。但根据我的研究,这不是代码问题,而是机器本身的问题。

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

System.Net.ServicePointManager.Expect100Continue = false;

似乎在服务器中有一个代理不支持100连续的行为。

System.Net.ServicePointManager.Expect100Continue = false;

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

我的具体案例场景是 Azure 应用程序服务的最小 TLS 版本改为1.2

我不知道从现在开始这是不是默认设置,但是把它改回1.0就行了。

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

我们有一个非常类似的问题,即客户端的网站试图连接到我们的 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

我对 还有一个问题的回答是这样的 Powershell 脚本,我们用它来添加条目:

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

这种情况发生在我身上的原因是我在 DI 提供程序中有一个递归依赖项。我的情况是:

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

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

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

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

有一个类似的问题,并得到以下错误取决于我使用的应用程序,如果我们绕过防火墙/负载平衡器或没有:

HTTPS 的握手失败(# 136)。 无法从传输中读取数据 连接: 现有连接被远程强制关闭 主持人

还有

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

问题是 SSL 服务器证书丢失了,没有安装在几台服务器上。

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

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

在我的例子中,错误代码是“发送失败”,因为在 HTTPS URL 上有证书问题,一旦我点击 HTTP,问题就解决了。

Https://learn.microsoft.com/en-us/dotnet/api/system.net.webexceptionstatus?redirectedfrom=msdn&view=netframework-4.8

根据“ Hans Vonn”的回复。

在打电话之前加上以下一行就解决了这个问题:

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

在添加安全协议和工作良好,但我必须添加之前,每个 API 调用,这是不健康的。我只是升级而已。Net 框架版本至少4.6,并按预期工作不需要添加之前,每个 API 调用。

对我来说,这是一个问题,在 IIS 绑定中它有 Web 服务器的 IP 地址。 我改变了它使用所有未分配的 IP 和我的应用程序开始工作。

我在使用 adomd 运行对 Microsoft 分析服务的 mdx 查询时遇到了这个错误

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

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

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

请确保在 web.config 文件中查看以下代码行:

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

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

我将 targetFramework 更改为4.7.2,问题就消失了:

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

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

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

System.Net.ServicePointManager.Expect100Continue = false;

详情

我收到这个错误仅仅是因为我试图建立一个 http 连接到一个 https-only 服务器。将 URI 中的请求协议从 http 更改为 https 从而解决了这个问题。

我就是这样解决问题的:

                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);

默认情况下,webrerequest 用户代理为 null。只要谷歌“块空用户代理”,你会发现很多网络服务器管理员的强烈愿望这样做。

把我的请求发给 request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0"; 解决了问题。

  • 我是从 控制台应用程序发送 HttpWebRequest 的,而 UserAgent 是 (默认情况下)为 null,因此设置 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";