重用异步套接字:后续连接尝试失败
Posted
技术标签:
【中文标题】重用异步套接字:后续连接尝试失败【英文标题】:Reuse asynchronous socket: subsequent connect attempts fail 【发布时间】:2011-04-23 04:57:14 【问题描述】:我正在尝试在异步 HTTP 客户端中重用套接字,但第二次无法连接到主机。我基本上将我的异步 HTTP 客户端视为具有以下状态的状态机:
Available:套接字可用 正在连接:套接字正在连接到端点 正在发送:套接字正在向端点发送数据 正在接收:套接字正在从端点接收数据 失败:出现套接字故障 清理:清理套接字状态在连接状态我调用BeginConnect
:
private void BeginConnect()
lock (_sync) // re-entrant lock
IPAddress[] addersses = Dns.GetHostEntry(_asyncTask.Host).AddressList;
// Connect to any available address
IAsyncResult result = _reusableSocket.BeginConnect(addersses, _asyncTask.Port, new AsyncCallback(ConnectCallback), null);
一旦成功建立连接,回调方法将状态更改为Sending
:
private void ConnectCallback(IAsyncResult result)
lock (_sync) // re-entrant lock
try
_reusableSocket.EndConnect(result);
ChangeState(EClientState.Sending);
catch (SocketException e)
Console.WriteLine("Can't connect to: " + _asyncTask.Host);
Console.WriteLine("SocketException: 0 Error Code: 1", e.Message, e.NativeErrorCode);
ThreadPool.QueueUserWorkItem(o =>
// An attempt was made to get the page so perform a callback
ChangeState(EClientState.Failed);
);
在清理中,我 Shutdown
套接字和 Disconnect
带有重用标志:
private void CleanUp()
lock (_sync) // re-entrant lock
// Perform cleanup
if (_reusableSocket.Connected)
_reusableSocket.Shutdown(SocketShutdown.Both);
_reusableSocket.Disconnect(true);
ChangeState(EClientState.Available);
对BeginConnect
的后续调用会导致超时和异常:
SocketException:连接尝试 失败是因为关联方做了 一段时间后无法正确响应 时间,或建立连接失败 因为连接的主机未能 回复 XX.XXX.XX.XX:80
错误代码:10060
这是状态跟踪:
Initializing...
Change State: Connecting
Change State: Sending
Change State: Receiving
Change State: CleanUp
Callback: Received data from client 0 // <--- Received the first data
Change State: Available
Change State: Connecting // <--- Timeout when I try to reuse the socket to connect to a different endpoint
我必须做些什么才能重用套接字连接到不同的主机?
注意:我没有尝试重新连接到同一台主机,但我认为发生了同样的事情(即无法连接)。
更新 我在documentation of BeginConnect 中找到了以下注释:
如果此套接字先前已断开连接,则必须在一个线程上调用 BeginConnect,该线程在操作完成之前不会退出。这是底层提供者的限制。使用的端点也必须不同。
我开始怀疑我的问题是否与此有关...我正在连接到不同的 EndPoint,但它们意味着我们调用 BeginConnect 的线程在操作完成之前不能退出?
更新 2.0: 我问了related question,我尝试使用“Async family”调用而不是“Begin family”调用,但我遇到了同样的问题!!!
【问题讨论】:
【参考方案1】:我评论了这个问题:what is benefit from socket reuse in C# about socket reuse using Disconnect(true)/DisconnectEx()
,这可能会对你有所帮助。
我个人认为这是对客户端代码的优化。
重新更新 1 到您的问题;不,如果是这种情况,您会收到 AbortedOperation 异常(请参见此处:VB.NET 3.5 SocketException on deployment but not on development machine),并且如果您在 Vista 或更高版本上运行,则文档是错误的,因为它不强制“线程必须存在直到重叠之后I/O 完成”以前的操作系统强制执行的规则。
正如我在对链接问题的回复中已经说过的那样;使用此功能建立出站连接几乎没有意义。很可能它最初被添加到 Winsock API 以支持在入站连接上 AcceptEx()
的套接字重用,其中,在使用 TransmitFile()
向客户端发送文件的非常繁忙的 Web 服务器上(这是重用断开连接似乎起源)。文档指出它不能很好地与TIME_WAIT
配合使用,因此将它用于启动主动关闭的连接(因此将套接字放入TIME_WAIT
,请参阅here)并没有真正的意义。
您能解释一下为什么您认为这种微优化在您的情况下实际上是必要的吗?
【讨论】:
我不知道为什么我没有回答你的问题,但我做这种微优化的原因是因为我每秒抓取 300 多个网页,每次抓取都需要我关闭旧的插座,处理掉它并打开一个新的。该应用程序运行时间很长,因此最终会导致内存抖动并减慢系统速度。在这种情况下,性能是关键。【参考方案2】:您是否检查了 MaxConnections 设置? http://msdn.microsoft.com/de-de/library/system.servicemodel.nettcpbinding.maxconnections.aspx
【讨论】:
看起来NetTcpBinding
是 WCF 的东西,我正在使用原始 Socket
s... 我不知道如何使用 NetTcpBinding
和原始 Socket
.
UPS。我认为它是一样的。我通常把它放到应用程序配置中: 以上是关于重用异步套接字:后续连接尝试失败的主要内容,如果未能解决你的问题,请参考以下文章