我寫了一個簡單的測試程序,使用兩種不同的技術來完成您的目標,以及測試您發佈的確切代碼。我無法重現您所描述的問題。無論我是直接使用TcpClient
還是Socket
,在對象上調用Close()
都會導致連接操作立即完成(在所有異步完成,異常處理,線程同步等完成後,小於1/10秒)
請注意,在TcpClient
的情況下,TcpClient
類似乎有一個錯誤,因爲它會拋出NullReferenceException
而不是(如預期的那樣)ObjectDisposedException
。這似乎是因爲TcpClient
在調用Close()
時將Client
屬性設置爲null
,但在調用完成委託時嘗試使用該值。哎呀。
這意味着在您的代碼中,調用者將看到NullReferenceException
而不是您似乎想要拋出的Exception
。但這似乎並不會造成實際的延遲本身。
這裏是我的測試程序:
class Program
{
static void Main(string[] args)
{
_TestWithSocket();
_TestWithTcpClient();
try
{
_TestSOCode();
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e);
}
}
private static void _TestSOCode()
{
using (var tcp = new TcpClient())
{
var c = tcp.BeginConnect(IPAddress.Parse("8.8.8.8"), 8080, null, null);
var success = c.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (!success)
{
Console.WriteLine("Before cleanup");
tcp.Close();
tcp.EndConnect(c);
Console.WriteLine("After cleanup");
throw new Exception("Failed to connect.");
}
}
}
private static void _TestWithTcpClient()
{
TcpClient client = new TcpClient();
object o = new object();
Console.WriteLine("connecting TcpClient...");
client.BeginConnect("8.8.8.8", 8080, asyncResult =>
{
Console.WriteLine("connect completed");
try
{
client.EndConnect(asyncResult);
Console.WriteLine("client connected");
}
catch (NullReferenceException)
{
Console.WriteLine("client closed before connected: NullReferenceException");
}
catch (ObjectDisposedException)
{
Console.WriteLine("client closed before connected: ObjectDisposedException");
}
lock (o) Monitor.Pulse(o);
}, null);
Thread.Sleep(1000);
Stopwatch sw = Stopwatch.StartNew();
client.Close();
lock (o) Monitor.Wait(o);
Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine();
}
private static void _TestWithSocket()
{
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
object o = new object();
Console.WriteLine("connecting Socket...");
socket.BeginConnect("8.8.8.8", 8080, asyncResult =>
{
Console.WriteLine("connect completed");
try
{
socket.EndConnect(asyncResult);
Console.WriteLine("socket connected");
}
catch (ObjectDisposedException)
{
Console.WriteLine("socket closed before connected");
}
lock (o) Monitor.Pulse(o);
}, null);
Thread.Sleep(1000);
Stopwatch sw = Stopwatch.StartNew();
socket.Close();
lock (o) Monitor.Wait(o);
Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine();
}
}
不幸的是,你還沒有提供一個實際的完整的代碼示例演示了問題。如果在你的環境中,上面的代碼演示了你所描述的問題,因爲它在我的環境中不這樣做,這顯然意味着你的環境會導致問題。不同的操作系統版本,不同的.NET版本等。
在這種情況下,您應該具體說明可能相關的特定環境方面。
如果上面的代碼示例按照需要工作,並且沒有演示您描述的問題,那麼您只需要弄清楚代碼中存在哪些不同並導致問題。在這種情況下,如果您仍然無法找出問題,那麼您應該發佈a minimal, complete code example來證明問題。
可能重複的[如何設置TcpClient的超時?](http://stackoverflow.com/questions/17118632/how-to-set-the-timeout-for-a-tcpclient)另外,什麼是與手動處理*和*使用說明? – bzlm 2015-01-26 21:29:04
感謝您的評論,但是「使用」是否存在並不重要。您的鏈接解決方案不起作用,並存在於我的代碼中。這是類似的問題,因爲在這裏:http://stackoverflow.com/questions/27417990/app-hangs-for-20-secs-on-exit-after-tcpclient-beginconnect – Josh 2015-01-26 21:31:19
你找到解決辦法? – shahroz 2016-05-09 07:22:39