这篇文章中的答案
建议使用Timer
使用ConnectAsync
暂停连接尝试。如果发生超时,我不确定如何处理Socket
。
考虑以下示例
public static void Main (string[] args)
{
IPEndPoint ep = new IPEndPoint (new IPAddress (new byte []{ 127, 0, 0, 1 }), 9042);
var socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
var connectTimeoutMs = 50;
var tcs = new TaskCompletionSource<bool> ();
new Timer ((t) => {
tcs.SetException(new ConnectionTimeoutException());
((Timer) t).Dispose();
}).Change (connectTimeoutMs, Timeout.Infinite);
var eventArgs = new SocketAsyncEventArgs { RemoteEndPoint = ep };
eventArgs.Completed += Finisher (tcs);
if (socket.ConnectAsync (eventArgs)) {
// dealt synchronously
}
try {
tcs.Task.Wait (); // actually a ContinueWith
} catch (AggregateException e) {
if (e.InnerException is ConnectionTimeoutException) {
socket.Dispose (); // is this the appropriate place for this?
}
}
Thread.Sleep (10000);
}
public static EventHandler<SocketAsyncEventArgs> Finisher(TaskCompletionSource<bool> tcs) {
return (sender, e) => {
if (e.SocketError != SocketError.Success) {
tcs.TrySetException (new SocketException ((int)e.SocketError));
} else {
tcs.TrySetResult (true);
}
e.Dispose ();
};
}
class ConnectionTimeoutException : SocketException {
public ConnectionTimeoutException(): base((int) SocketError.TimedOut){}
}
在Mono-3.10.0上,如果发生超时,则会导致致命(未被捕获)ObjectDisposedException
Unhandled Exception:
System.ObjectDisposedException: The object was used after being disposed.
at System.Net.Sockets.Socket.EndConnect (IAsyncResult result) [0x00016] in /home/user/dev/mono-3.10/mono-3.10.0/mcs/class/System/System.Net.Sockets/Socket.cs:1274
at System.Net.Sockets.SocketAsyncEventArgs.ConnectCallback (IAsyncResult ares) [0x00000] in /home/user/dev/mono-3.10/mono-3.10.0/mcs/class/System/System.Net.Sockets/SocketAsyncEventArgs.cs:260
at System.Net.Sockets.SocketAsyncEventArgs.DispatcherCB (IAsyncResult ares) [0x000aa] in /home/user/dev/mono-3.10/mono-3.10.0/mcs/class/System/System.Net.Sockets/SocketAsyncEventArgs.cs:234
因为打电话给
socket.Dispose()
实际上完成了SocketAsyncEventArgs
,但首先验证相应的Socket
是否已被处置。 This was "corrected" in newer versions of Mono,但它让我想到这是否是在Socket
上超时连接尝试的合适模式。是吗?并且Completed
事件应该在基础Dispose
的{{1}}上提出(Socket
,不能少)?
解决方案看起来像
SocketError.Success