WCF: System.Net.SocketException - 通常情况下,每个套接字地址(协议/网络地址/端口)只允许使用一次

53

我有一个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

我在复现这种行为时遇到了麻烦。我确保在try..catch..finally块中关闭了客户端连接。仍然不理解是什么原因导致了这个问题..有人知道吗?

注意:我已经查看了这个SO问题,但似乎没有回答我的问题,所以这不是重复的问题。


这是因为 Web 服务使用了端口 80,而 IIS 也在使用该端口吗?你们的服务在生产环境中使用哪个端口?IIS 在生产环境中配置在哪个端口上? - shahkalpesh
两个应用程序的端口号都是80。WCF服务被配置为站点根目录下的虚拟目录。所以,您的意思是说网页请求和使用相同端口的服务请求之间可能会偶尔发生冲突? - asyncwait
我遇到了类似的情况。计划在WCF服务中使用net tcp端口共享功能。http://msdn.microsoft.com/en-us/library/ms734772.aspx请告诉我这是否有效。 - user272363
2个回答

85
您正在超载TCP/IP堆栈。Windows(我认为所有的套接字堆栈实际上也是如此)由于套接字在正常操作下如何关闭,有一个套接字可以在短时间内被打开的数量限制。每当一个套接字关闭时,它都会进入TIME_WAIT状态一段时间(我记得是240秒)。每次进行轮询时,一个套接字将从默认动态范围(我认为它位于1024以上的约5000个动态端口)中消耗掉,而每次该轮询结束时,该特定的套接字就会进入TIME_WAIT状态。如果您足够频繁地进行轮询,最终将消耗所有可用端口,这将导致TCP错误10048。
通常情况下,WCF通过连接池等方式来避免这个问题。这通常适用于不经过互联网的内部服务。我不确定任何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分钟的延迟)。

以上解决方案中的一个应该可以解决您的问题。如果在更改端口范围后问题仍然存在,建议尝试增加轮询的时间间隔,这样轮询发生的频率就会降低...这将为您提供更多的灵活性来解决时间等待延迟问题。将时间等待延迟更改作为最后一招。


嗯...这个链接http://msdn.microsoft.com/en-us/library/aa560610(v=bts.20).aspx中拼写参数TCPTimeWaitDelay的方式不同。它将其拼写为TcpTimedWaitDelay。我该如何确认哪一个是正确的呢? 更多信息请参考technet:http://technet.microsoft.com/en-us/library/cc938217.aspx - Jaans
正确的大小写是TcpTimeWaitDelay吗?如果是,我会修正答案。 - jrista
2
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay - granadaCoder
4
有没有计数器可以让我查看当前有多少连接在使用? - jfl
根据@Jaans引用的MSDN文章,TcpTimedWaitDelay的范围为30到300,默认值为240。单位为秒,jrista指出。 - AlainD
此注册表键在Windows 10上不可用。 - user5125586

12

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

我在 http://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ 上对此进行了详细说明。


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