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

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 的东西,我正在使用原始 Sockets... 我不知道如何使用 NetTcpBinding 和原始 Socket . UPS。我认为它是一样的。我通常把它放到应用程序配置中: 我认为套接字不受这些设置的影响。许多套接字应用程序甚至可能没有 app.config,但无论如何感谢您的回答:)。

以上是关于重用异步套接字:后续连接尝试失败的主要内容,如果未能解决你的问题,请参考以下文章

WSA UDP 套接字无法重用,因为它强制关闭连接

套接字是不是在重新连接事件中重用?

虽然没有来自客户端的连接操作,但服务器尝试接受连接并因“非套接字上的套接字操作”而失败

异步套接字和“静默”断开连接

我如何使用异步套接字在连接的客户端之间切换

在重新连接、socket.io、node.js 时重用套接字 id