51

我有一个 WCF 服务和一个 Web 应用程序。Web 应用程序以连续方式调用此 WCF 服务,即轮询。在我们的生产环境中,我很少收到此错误。因为,这是一个内部活动,用户不知道何时抛出此错误。

无法连接到 http://localhost/QAService/Service.svc。TCP 错误代码 10048:每个套接字地址(协议/网络地址/端口)通常只允许使用一次 127.0.0.1:80。---> System.Net.WebException:无法连接到远程服务器 ---> System.Net.Sockets.SocketException:每个套接字地址(协议/网络地址/端口)通常只允许使用一次 127.0.0.1 :80

我在我们的 dev/qa 环境中重现此行为时遇到了麻烦。我已确保客户端连接在 try..catch..finally 块中关闭。仍然不明白是什么导致了这个问题..有人知道这一点吗?

注意:我看过这个SO question,但似乎没有回答我的问题,所以它不是重复的问题。

4

2 回答 2

84

您正在超载 TCP/IP 堆栈。Windows(我认为实际上所有套接字堆栈)对可以快速打开的套接字数量有限制,因为套接字在正常操作下是如何关闭的。每当一个套接字关闭时,它就会进入 TIME_WAIT 状态一段时间(240 秒 IIRC)。每次轮询时,都会消耗默认动态范围之外的套接字(我认为它大约有 5000 个动态端口,刚好高于 1024),并且每次轮询结束时,该特定套接字都会进入 TIME_WAIT。如果轮询足够频繁,最终将消耗所有可用端口,这将导致 TCP 错误 10048。

通常,WCF 试图通过池化连接和类似的东西来避免这个问题。这通常是不通过 Internet 的内部服务的情况。我不确定是否有任何 wsHttp 绑定支持连接池,但 netTcp 绑定应该。我会假设命名管道不会遇到这个问题。我不能说 MSMQ 绑定。

您可以使用两种解决方案来解决此问题。您可以增加动态端口范围,也可以减少 TIME_WAIT 的周期。前者可能是更安全的路线,但如果您正在消耗大量的套接字(这听起来不像您的场景的情况),减少 TIME_WAIT 是一个更好的选择(或两者一起使用。)

更改动态端口范围

  1. 打开注册表。
  2. 打开密钥 HKLM\System\CurrentControlSet\Services\Tcpip\Parameters
  3. 编辑(或创建为 DWORD)MaxUserPort 值。
  4. 将其设置为更高的数字。(即 65534)

更改 TIME_WAIT 延迟

  1. 打开注册表。
  2. 打开密钥 HKLM\System\CurrentControlSet\Services\Tcpip\Parameters
  3. 编辑(或创建为 DWORD)TcpTimedWaitDelay。
  4. 将其设置为较低的数字。值以秒为单位。(即 60 延迟 1 分钟)

上述解决方案之一应该可以解决您的问题。如果它在更改端口范围后仍然存在,我会尝试增加轮询的周期,以减少它发生的频率……这将为您提供更多的回旋余地来解决时间等待延迟。作为最后的手段,我会更改时间等待延迟。

于 2009-08-27T06:41:10.343 回答
11

HttpClient,虽然它实现了IDisposable是一个共享对象,但是你应该尽可能的减少实例的数量。您可以在应用程序的整个生命周期中只使用一个实例,而不是为每个请求创建一个实例。

我在http://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/上写了很多关于它的文章

于 2016-09-01T19:09:15.260 回答