我正在尝试在异步HTTP客户端中重用套接字,但是第二次我无法连接到主机。我基本上将异步HTTP客户端视为具有以下状态的状态机:
在连接状态下,我拨打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
我需要做些什么才能重用套接字连接到其他主机?
注意:我有 not 试图重新连接到同一主机,但我假设同样的事情发生(即无法连接)。
更新
我在documentation of BeginConnect中找到了以下注释:
如果此套接字先前已断开连接,则必须在线程上调用BeginConnect,该线程在操作完成之前不会退出。这是底层提供者的限制。此外,使用的EndPoint必须不同。
我开始怀疑我的问题是否与此有关...我正在连接到另一个EndPoint,但它们是什么意思是我们称之为BeginConnect的线程必须不会退出,直到操作完成?
更新2.0:
我问了一个related question我尝试使用“Async family”调用而不是“Begin family”调用,但是我遇到了同样的问题!
答案 0 :(得分:2)
我对此问题发表了评论:what is benefit from socket reuse in C#关于使用Disconnect(true)/DisconnectEx()
进行套接字重用,这可能对您有所帮助。
就我个人而言,我认为客户代码中的优化太过分了。
重新更新1问题;不,你会得到一个AbortedOperation异常,如果是这种情况(参见这里:VB.NET 3.5 SocketException on deployment but not on development machine),如果你在Vista或更高版本上运行文档是错误的,因为它不强制执行“线程必须存在,直到重叠后的I / O完成“以前操作系统强制执行的规则。
正如我在回答相关问题时已经说过的那样;将此功能用于出站连接建立没有什么意义。它可能最初被添加到Winsock API以支持入站连接上AcceptEx()
的套接字重用,其中,在一个非常繁忙的Web服务器上,使用TransmitFile()
将文件发送到客户端(这是对于重用的断开似乎已经产生了)。文档声明它与TIME_WAIT
不兼容,因此将它用于启动主动关闭的连接(因此将套接字放入TIME_WAIT
,请参阅here)不要真的很有道理。
你能解释为什么你认为这种微观优化在你的情况下确实是必要的吗?
答案 1 :(得分:0)