重用异步套接字:后续连接尝试失败

本文关键字:连接 失败 异步 套接字 | 更新日期: 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