重用异步套接字:后续连接尝试失败
本文关键字:连接 失败 异步 套接字 | 更新日期: 2023-09-27 17:52:12
我试图在异步HTTP客户端中重用套接字,但我无法第二次连接到主机。基本上,我将异步HTTP客户端视为具有以下状态的状态机:
- Available: socket可用
- 正在连接:套接字正在连接到端点
- 发送:套接字正在发送数据到端点
- 接收:套接字正在从端点 接收数据
- Failed: there was a socket failure
- Clean Up:清除socket状态
在连接状态下,我调用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);
});
}
}
}
在清理I 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
我必须做些什么才能重用套接字连接到不同的主机?
注意:我有不是试图重新连接到同一主机,但我认为发生了同样的事情(即连接失败)。
我在BeginConnect的文档中发现了以下注释:
如果此套接字先前已断开连接,则必须在一个直到操作完成才退出的线程上调用BeginConnect。这是底层提供程序的限制。此外,所使用的端点也必须不同。
我开始怀疑我的问题是否与此有关…我正在连接到一个不同的端点,但是它们意味着我们调用BeginConnect的线程必须在操作完成之前不退出?
更新2.0:
我问了一个相关的问题,我尝试使用"Async家族"调用而不是"Begin家族"调用,但我得到同样的问题!!
我评论了这个问题:在c#中使用Disconnect(true)/DisconnectEx()
重用套接字有什么好处,这可能会对你有所帮助。
我个人认为这在客户端代码中优化得太远了。
对你的问题重新更新1;不,如果是这种情况,你会得到一个AbortedOperation异常(参见这里:VB)。如果你在Vista或更高版本上运行,则文档是错误的,因为它不强制以前操作系统强制的"线程必须存在直到重叠I/O完成"规则。
正如我在回答相关问题时已经说过的;将此功能用于建立出站连接没有什么意义。很可能它最初被添加到Winsock API中,以支持入站连接上AcceptEx()
的套接字重用,其中,在一个非常繁忙的web服务器上,使用TransmitFile()
向客户端发送文件(这就是disconnect for reuse的起源)。文档指出,它不能很好地与TIME_WAIT
配合使用,因此将它用于发起活动关闭的连接(从而将套接字放入TIME_WAIT
,见这里)实际上没有意义。
你能解释一下为什么你认为这种微优化实际上是必要的吗?
是否检查了MaxConnections设置?http://msdn.microsoft.com/de-de/library/system.servicemodel.nettcpbinding.maxconnections.aspx