【问题标题】:.NET socket timeout - blocking on Close method.NET 套接字超时 - 阻塞关闭方法
【发布时间】:2011-02-27 16:40:51
【问题描述】:

我在使用异步套接字调用实现连接超时时遇到问题。

我的想法是我在 Socket 对象上调用 BeginConnect,然后在超时期限过后使用计时器在套接字上调用 Close()

只要在 GUI 线程上创建套接字就可以正常工作 - Close 方法立即返回,并执行回调方法。但是,如果套接字是在任何其他线程上创建的,则 Close 方法会阻塞,直到发生默认 IP 超时。

要重现的代码:

private Socket client;

private void button1_Click(object sender, EventArgs e) {
    // Creating the socket on a threadpool thread causes Close to block.
    ThreadPool.QueueUserWorkItem((object state) => {
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IAsyncResult result = client.BeginConnect(IPAddress.Parse("144.1.1.1"), 23, new AsyncCallback(CallbackMethod), client);

        // Wait for 2 seconds before closing the socket.
        if (result.AsyncWaitHandle.WaitOne(2000)) {
            MessageBox.Show("Connected.");
        } else {
            MessageBox.Show("Timed out. Closing socket...");
            client.Close();
            MessageBox.Show("Socket closed.");
        }
    });
}

private void CallbackMethod(IAsyncResult result) {
    MessageBox.Show("Callback started.");
    Socket client = result.AsyncState as Socket;
    try {
        client.EndConnect(result);
    } catch (ObjectDisposedException) {
    }
    MessageBox.Show("Callback finished.");
}

如果删除 QueueUserWorkItem 行,在 GUI 线程上创建套接字,套接字会立即关闭而不会阻塞。

谁能解释一下发生了什么?
谢谢。

编辑 - System.Net 跟踪输出似乎有所不同,具体取决于它是连接到 GUI 线程还是不同的线程:

【问题讨论】:

    标签: c# .net sockets


    【解决方案1】:

    您是否尝试过在调用 Socket.Close() 时移除“MessageBox.Show”调用?

    【讨论】:

    • 无论MessageBox.Show如何,都会发生关闭时的阻塞。即使将 Socket 的 LingerState 属性设置为 true 且超时时间为零也无济于事。来自 MSDN:“下表描述了 Close 方法对存储在 LingerState 属性中的 Enabled 属性和 LingerTime 属性的可能值的行为。”启用 LingerState 并将 LingerTime 设置为零:“丢弃任何待处理的数据。对于面向连接的套接字(例如 TCP),Winsock 会重置连接。”
    • 我尝试使用上述程序进行复制。我无法复制它。程序没有挂起。
    • 这发生在我的 Windows 7 和 XP 模式下,在任何版本的 .NET Framework 上。我也可以在另一台机器上重现它。程序不应挂起,但在“超时。正在关闭套接字...”消息和“套接字已关闭”之间应该有大约 20 秒的延迟。消息。
    • 嗯。尝试获取跟踪日志(请参阅ferozedaud.blogspot.com/2009/08/tracing-with-systemnet.html)并将日志文件放在 pastebin.com 上。我可以看看。
    • 谢谢您,我已经编辑了我的问题以包含跟踪日志。似乎底层套接字调用因调用它们的线程而异。
    【解决方案2】:

    我想不通的是为什么它会在 GUI 线程上立即关闭。我会在调用 client.Close() 之前尝试调用 client.Shutdown()。

    我也会尝试在常规线程 (Thread.Start()) 中运行套接字对象,而不是使用 ThreadPool。这样您就可以保留对线程的引用并自己调用 Thread.Interrupt() 和/或 Thread.Abort()。

    【讨论】:

    • 在套接字连接之前调用 Shutdown 会导致 SocketException -“发送或接收数据的请求被禁止,因为套接字未连接并且(使用 sendto 调用在数据报套接字上发送时)否地址已提供”。我目前正在使用单个线程来启动许多 BeginConnect,然后使用 System.Timers.Timer 根据需要使套接字超时 - 我无法为每个连接都使用新线程。 :(
    猜你喜欢
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多