远程主机强制关闭了现有的连接

242

我正在使用一款商业应用程序,它会抛出一个SocketException异常,并显示以下消息:

现有的连接已被远程主机强制关闭

这种情况发生在客户端和服务器之间的socket连接中。尽管连接是正常并且大量数据正在传输,但突然之间连接就断开了。

有人以前遇到过这种情况吗?可能的原因是什么?我可以猜测几个原因,但是是否有任何方法可以添加更多代码以找出原因呢?

欢迎任何评论/想法。

...最新消息...

我从.NET跟踪日志中获得了一些日志记录信息,

System.Net.Sockets Verbose: 0 : [8188] Socket#30180123::Send() DateTime=2010-04-07T20:49:48.6317500Z

System.Net.Sockets Error: 0 : [8188] Exception in the Socket#30180123::Send - An existing connection was forcibly closed by the remote host DateTime=2010-04-07T20:49:48.6317500Z 

System.Net.Sockets Verbose: 0 : [8188] Exiting Socket#30180123::Send() -> 0#0
基于我所看到的日志信息,这里的0#0表示正在发送一个长度为0字节的数据包。但是这真正意味着什么呢?有两种可能性,我不确定哪一种是:

  1. 连接已关闭,但是数据还在被写入套接字,因此引发了上述异常。 0#0表示由于套接字已关闭而未发送任何内容。

  2. 连接仍然打开,并且正在发送一个长度为零字节的数据包(即代码存在错误),而0#0表示正在尝试发送一个长度为零字节的数据包。

你认为呢?可能会无法确定,但也许其他人见过类似的情况?

只是一个更新。由于我们的网络设置,似乎Wireshark在这种情况下行不通。但我希望尝试一下这个链接:http://blogs.msdn.com/dgorti/archive/2005/09/18/471003.aspx,它使用.NET进行跟踪,应该会生成一些日志文件。我会随时向您报告... - peter
1
Comcast 也以发送伪造 ID 的“零”数据包来干扰 P2P 流量而闻名。 - user1335322
20个回答

151

一般来说,这意味着远程端关闭了连接(通常是通过发送TCP/IP的 RST 包)。如果您正在使用第三方应用程序,可能的原因如下:

  • 您向应用程序发送了格式不正确的数据(可能包括向HTTP服务器发送HTTPS请求)
  • 客户端和服务器之间的网络链接由于某种原因而断开
  • 您触发了第三方应用程序中导致其崩溃的错误
  • 第三方应用程序已经耗尽了系统资源

很可能是第一种情况导致了问题的出现。

您可以启动 Wireshark 来查看网络传输情况,以缩小问题范围。

没有更具体的信息,这里的任何人都不太可能真正帮助您。


2
太好了。谢谢。关于Wireshark的另一件事。它收集了如此多的数据,我怎么能够过滤出这样的东西呢?如果Wireshark显示了什么,我以后可能会在这里发布... - peter
5
你应该能够按IP地址和端口号过滤Wireshark的数据包转储,至少如此。然后,最有帮助的可能是查看流的结尾(出了问题的地方),并向后工作,直到你能够发现事情出错的地方。根据所涉及协议的复杂性,这可能非常容易或几乎不可能... - RarrRarrRarr
4
这些项目符号的来源是什么?还是下面Gamer的回答只是复制了你的清单? - Zack
13
请注意,“发送格式不正确的数据”可能意味着向“http”服务器发送“https”请求,反之亦然。 - AXMIM
4
在我的案例中,只有在本地运行应用程序时调用API时才会出现此异常。在开发、QA或生产环境中没有任何问题。解决方法是在本地使用HTTP而不是HTTPS。我们认为这可能与负载均衡器有关。但我们刚刚更新了开发、QA和生产环境的Web.config文件,使用HTTPS转换。问题已经解决。 - Kershaw
显示剩余3条评论

145

使用TLS 1.2解决了这个错误。
你可以通过以下方式强制应用程序使用TLS 1.2(确保在调用服务之前执行它):

使用TLS 1.2解决了这个错误。
您可以通过以下方法强制应用程序使用TLS 1.2(请确保在调用服务之前执行此操作):

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 

另外一种解决方案:
启用本地机器或服务器中的强密码学,以便使用TLS1.2,因为默认情况下它被禁用,所以只使用TLS1.0。
要启用强密码学,在 PowerShell 中使用管理员特权执行以下命令:

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord 

为了让这些更改生效,您需要重新启动计算机。


2
您可以将多个值相加以支持多个协议。因此,要支持从SSL3到TLS1.2的所有内容,请设置SecurityProtocol =(SecurityProtocolType)4080。 - Abacus
1
愚蠢的问题:我有两个服务器。其中一个服务器存在此问题,但另一个正常工作。我正在尝试确定这些服务器之间的区别。我甚至没有在它们中的任何一个中看到注册表键“SchUseStrongCrypto”。当该键不存在时意味着什么?它会使用默认的TLS吗? - Vin Shahrdar
对于那些使用Windows且无法访问导致问题的程序的原始源代码的人,您可以运行以下脚本,该脚本生成其他脚本以在操作系统级别修复任何潜在的TLS兼容性问题(它是特定于DevOps的,但也可能适用于其他情况):https://github.com/microsoft/azure-devops-tls12/blob/main/AzureDevOpsTls12Analysis.ps1(注意:我发现我实际上必须使用“git clone”克隆存储库-仅复制文件内容会导致编码问题,因此我无法运行脚本)。 - George Howarth

35

这不是你代码中的错误。它来自于 .Net 的 Socket 实现。如果你使用如下的重载实现 EndReceive,你就不会遇到这个异常。

    SocketError errorCode;
    int nBytesRec = socket.EndReceive(ar, out errorCode);
    if (errorCode != SocketError.Success)
    {
        nBytesRec = 0;
    }

1
这是来自操作系统,最终来自对等方的信息。需要进一步解释它是软件漏洞的指控。 - user207421
7
在我的 C# 程序中,当客户端正常终止连接时,我一直在思考为什么 EndReceive 会抛出异常。我不知道这是设计上的原因。我认为在正常代码流程中抛出异常是糟糕的设计。感谢有重载方法。 - Pavan Manjunath
@pavanManjunath,怎么做这个:( 你能帮我吗? - Khalil Khalaf
2
@MSaudi 这是使用异步调用,确保您理解在处理返回的数据时,代码不会停止。示例使用 https://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx 。基本上,您必须拥有一个 StateObject 类,其中包含 public byte[] buffer = new byte[1024], public Socket socket; 并调用名为 Receive(Socket s) 的函数,该函数执行 StateObject so = new StateObject(); so.socket = s; s.BeginReceive(so.buffer, 0, 256, 0, new AsyncCallback(ReceiveCallback), so); ,并在 void ReceiveCallback(IAsyncResult ar) 中调用上述代码。 - vapcguy
2
虽然它提供了一种解决方案,但我从未看到异步方法的价值,因为在你执行Send之后,在你可以执行其他任何操作之前,你需要立即知道返回的内容是什么。 - vapcguy
3
实际上,我发现这种方法并不是百分之百可靠的。它也可能导致与此类似的错误:https://dev59.com/63TYa4cB1Zd3GeqPyb8t?rq=1 - vapcguy

13

我也遇到了同样的问题。如果使用代理发送流量(在我的情况下是Fiddler),就能正常工作。将.NET框架从4.5.2更新到>=4.6,现在一切都运行良好。实际请求代码如下:
new WebClient().DownloadData("URL");
异常信息为:

SocketException:远程主机强制关闭了一个现有的连接。


8
这对我来说是解决问题的一种方式。实际上,这与.NET默认使用哪个版本的TLS有关。4.5.2及以下版本使用TLS1.0,而4.6及更高版本则更加聪明,允许1.1和1.2。通过将服务器上的TLS要求降低到1.0,也可以证明这一点,这同样解决了问题。 - HotN

7

针对这个常见的烦人问题,有一个简单的解决方案:

只需前往您的“.context.cs”文件(位于您的“*.edmx”文件下方的“.context.tt”下),然后在构造函数中添加以下行:

public DBEntities() 
        : base("name=DBEntities") 
    { 
        this.Configuration.ProxyCreationEnabled = false; // ADD THIS LINE!
    }

3
这是一个玩笑回答吗?Entity Framework 6代理与这个问题所涉及的网络/套接字完全无关。 - 0xced

5
我因实体中的循环引用而遇到了此异常。这个实体看起来像:
public class Catalog
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public Catalog Parent { get; set; }
    public ICollection<Catalog> ChildCatalogs { get; set; }
}

我给Parent属性添加了[IgnoreDataMemberAttribute],这解决了问题。


4

如果运行在 .Net 4.5.2 Service 中

对于我来说,这个问题变得更为复杂,因为调用是在 .Net 4.5.2 服务中运行的。我按照@willmaz的建议进行操作,但出现了一个新的错误。

在打开日志记录的情况下运行服务时,我查看了与目标站点的握手过程,一切都正常(并发送了承载令牌),但在处理 Post 调用的以下步骤中,它似乎放弃了身份验证令牌,站点会回复“未授权”。

解决方案

事实证明,服务池凭据没有更改 TLS (?) 的权限,当我将本地管理员帐户放入池中时,一切正常。


2

我曾经遇到同样的问题,最终成功解决了。在我的情况下,客户端发送请求的端口没有与 SSL 证书进行绑定。因此,我在服务器端将 SSL 证书绑定到了该端口,问题得以解决。这样一来,异常就消失了。


2

我在使用.NET Framework 4.5时遇到了同样的问题。然而,当我将.NET版本更新到4.7.2时,连接问题得到了解决。也许这是由于安全协议支持问题所致。


2
对于任何在读取数据流时遇到此异常的人,这可能会有所帮助。当我像这样循环读取HttpResponseMessage时,我遇到了这个异常:
using (var remoteStream = await response.Content.ReadAsStreamAsync())
using (var content = File.Create(DownloadPath))
{
    var buffer = new byte[1024];
    int read;

    while ((read = await remoteStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
    {
        await content.WriteAsync(buffer, 0, read);
        await content.FlushAsync();
    }
}

过了一段时间,我发现罪魁祸首是缓冲区大小太小,与我的弱Azure实例不兼容。改变代码为以下内容有所帮助:
using (Stream remoteStream = await response.Content.ReadAsStreamAsync())
using (FileStream content = File.Create(DownloadPath))
{
    await remoteStream.CopyToAsync(content);
}

“CopyTo()”方法的默认缓冲区大小为81920。较大的缓冲区可以加快进程,并立即停止错误,很可能是因为整体下载速度增加了。但为什么下载速度会影响防止此错误呢?
可能是因为下载速度低于服务器配置的最小阈值而导致与服务器断开连接。例如,如果您正在从IIS托管的应用程序下载文件,则可能存在http.sys配置问题:
“Http.sys是IIS使用的http协议栈,用于与客户端执行http通信。它有一个名为MinBytesPerSecond的计时器,负责在其传输速率低于某些kb / sec阈值时终止连接。默认情况下,该阈值设置为240 kb / sec。”
该问题在TFS开发团队的旧博客文章中描述,并涉及IIS特定问题,但可能指向正确的方向。它还提到了与此http.sys属性相关的旧错误:link 如果您正在使用Azure应用服务,增加缓冲区大小无法解决问题,请尝试升级您的机器。这样,您将获得更多资源,包括连接带宽。

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