HttpClient:每个套接字地址(协议/网络地址/端口)通常只允许使用一次
Posted
技术标签:
【中文标题】HttpClient:每个套接字地址(协议/网络地址/端口)通常只允许使用一次【英文标题】:HttpClient: Only one usage of each socket address (protocol/network address/port) is normally permitted 【发布时间】:2014-10-17 15:52:08 【问题描述】:using (var client = new HttpClient())
client.BaseAddress = new Uri(Url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
using (var task = client.PostAsJsonAsync(Url, body))
if (task.Result.StatusCode != HttpStatusCode.OK)
throw new Exception(task.Result.ReasonPhrase);
不知道为什么我们得到每个套接字地址(协议/网络地址/端口)的唯一一种用法通常是允许的 xx.xxx.xxx.xx:80 错误
System.AggregateException: One or more errors occurred. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted xx.xx.xx.xx:80
at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
【问题讨论】:
【参考方案1】:有问题的错误是WSAEADDRINUSE
(10048):
地址已在使用中。 通常,每个套接字仅使用一次 地址(协议/IP 地址/端口)是允许的。如果发生此错误 应用程序尝试将套接字绑定到 IP 地址/端口 已用于现有套接字,或未使用的套接字 正确关闭,或仍在关闭过程中。为了 需要将多个套接字绑定到同一个套接字的服务器应用程序 端口号,考虑使用 setsockopt (SO_REUSEADDR)。客户 应用程序通常根本不需要调用 bind——connect 选择一个 自动使用未使用的端口。当使用通配符地址调用 bind 时 (涉及 ADDR_ANY),WSAEADDRINUSE 错误可能会延迟到 提交具体地址。这可能发生在调用 稍后的另一个函数,包括 connect、listen、WSAConnect 或 WSAJoinLeaf。
这意味着您有多个 HttpClient
对象试图同时将自己绑定到同一个本地 IP/端口,或者另一个应用程序正在使用 HttpClient
也尝试使用的 IP/端口。
更有可能的是,您可能过于频繁地发布 HTTP 请求,并且可能没有完全消耗响应,这将阻止 ASP 池化和重用连接,从而随着时间的推移遇到端口耗尽。
【讨论】:
谢谢。这说得通。我在不同的线程中有多个 HttpClient 实例,一个 HttpClient 实例如何知道另一个线程中的另一个 HttpClient 实例正在使用哪个 ip/port? 再次感谢雷米。现在我明白了为什么会出现这个错误。 来自 Henrik Nielsen:这通常是因为您的临时端口用完了。尝试为所有请求重用相同的 HttpClient 实例 @TonyBao 所以如果 TCP 连接总是在同一个客户端和服务器之间,重用同一个 HttpClient 是否意味着服务器总是看到相同的原始地址和端口? @Dibzmania 这取决于 HttpClient 是否重用相同的 TCP 连接,或者 TCP 连接是否关闭然后新的 TCP 连接使用相同的本地 IP/端口【参考方案2】:我在尝试向一台服务器发送 200 个请求/秒的负载生成器工具中遇到了同样的问题。
我从每个请求的新 HttpClient 实例转移到一个单例,它确实解决了这个问题。
注意 - 最初我遇到了 2 个请求/秒的瓶颈,但将 DefaultConnectionLimit 设置为 500 解决了它:
ServicePointManager.DefaultConnectionLimit = 500;
【讨论】:
【参考方案3】:最近在 Windows 2012 R2 环境中运行多年的现有客户端/服务器 Web 服务设置中遇到了这个问题。
这个问题只会在很长一段时间后才会出现。 问题发生在传出客户端连接上,而不是服务器上的侦听套接字。 使用 netstat 我们可以看到有足够多的可用套接字。 重启客户端服务并没有解决问题。 重新启动应用程序池/iis 重置无法解决问题。 重启服务器会在一段时间内解决问题。在按照帖子和 MS 文章的建议用尽所有检查并结合套接字连接知识后,我们认为这是一个较低级别的代码问题,我们聘请了 Microsoft 支持。
结果是 KB 4338824 存在一个已知问题 https://support.microsoft.com/en-us/help/4338824/windows-81-update-kb4338824
我解释一下.... “应用程序和服务可能会在 closesocket() 调用中挂起,并导致应用程序或服务无法绑定到网络套接字。”
应用了以下补丁并解决了问题。 https://support.microsoft.com/en-us/help/4345424/improvements-and-fixes-windows-8-1-and-server-2012-r2
【讨论】:
【参考方案4】:以管理员身份运行命令提示符并键入以下命令。 netstat -ano | findstr ":80"
a:显示所有连接和侦听端口。 n:以数字形式显示地址和端口号。 o:显示与每个连接关联的所属进程 ID。如果您使用不同的端口号,请将 80 替换为适当的端口号。
结果将使用最后一列中的 80 端口号显示进程 ID。 您可以在程序中更改端口号,也可以使用 80 端口号终止进程。
【讨论】:
以上是关于HttpClient:每个套接字地址(协议/网络地址/端口)通常只允许使用一次的主要内容,如果未能解决你的问题,请参考以下文章
无法绑定地址 [10048]:每个套接字地址(协议/网络地址/端口)通常只允许使用一次
如何修复错误“每个套接字地址(协议/网络地址/端口)通常只允许使用一次”?
Windows socket error: 通常每个套接字地址(协议/网络地址/端口)只允许使用一次.(10048)
MySQL/PHP 错误:[2002] 每个套接字地址(协议/网络地址/端口)通常只允许使用一次
WCF:System.Net.SocketException - 每个套接字地址(协议/网络地址/端口)通常只允许使用一次