2010-06-04 26 views
1

我在使用异步套接字调用实现连接超时时遇到问题。.NET套接字超时 - 在关闭方法上阻塞

这个想法是我在一个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线程或者不同的线程上是不同的:

回答

0

有您尝试删除您在调用Socket.Close()时所使用的“MessageBox.Show”调用?

+0

无论MessageBox.Show如何,封闭都会发生。 即使将套接字的[LingerState](http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.lingerstate.aspx)属性设置为true,但不会超时帮帮我。 从MSDN:“下表描述了对于Enabled属性和LingerTime属性中存储的LingerState属性的可能值的Close方法的行为。” 启用LingerState并且将LingerTime设置为零:“丢弃任何未决数据。对于面向连接的套接字(例如TCP),Winsock重置连接。” – Mark 2010-06-05 03:52:06

+0

我试着用上面的程序重新编译。我无法复制它。该程序不挂。 – feroze 2010-06-08 03:16:47

+0

在Windows 7和XP模式下,在任何版本的.NET Framework上,都会出现这种情况。我也可以在不同的机器上重现它。该程序不应该挂起,但在“超时,关闭套接字...”消息和“套接字关闭”之间应该有大约20秒的延迟。信息。 – Mark 2010-06-10 20:51:29

0

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

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

+0

上的说明获取winsock跟踪日志。在套接字连接结果之前调用Shutdown SocketException - “发送或接收数据的请求被禁止,因为套接字未连接,并且(当使用sendto调用在数据报套接字上发送时)未提供地址”。 我目前使用单线程来启动许多BeginConnects,然后使用System.Timers.Timer来根据需要超时套接字 - 我无法负担为每个连接使用新的线程。 :( – Mark 2010-06-05 04:08:33