如何在StreamSocket的ConnectAsync()函数中设置超时时间?

7
在Windows Phone 8.1应用程序中,我必须创建以下套接字。我如何更改它,以便可以指定超时时间?
_socket = new StreamSocket();
await _socket.ConnectAsync(hostName, port.ToString(), SocketProtectionLevel.PlainSocket);

await _socket.InputStream.ReadAsync(frameLenData, frameLenData.Capacity, Windows.Storage.Streams.InputStreamOptions.None);

在我之前的 Windows Phone 代码中,我会创建 Socket 并通过测试 _event.WaitOne(timeout) 来设置超时时间,例如:

timeout = 5000;
_event = new ManualResetEvent(false);
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

bool bOperationFailed = false;
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = new DnsEndPoint(address, port);


_event.Reset();

_socket.ReceiveAsync(socketEventArg);

// Wait for completion
if (_event.WaitOne(timeout) == false)
{
    Trace.trace("timed out");
    return false;
}

我可以为StreamSocketConnectAsync()设置超时时间吗?如果可以,应该如何操作?

4个回答

8
使用CancellationTokenSource和AsTask扩展方法。
var cts = new CancellationTokenSource();
cts.CancelAfter(2000); // cancel after 2 seconds

var connectAsync = _socket.ConnectAsync( ... );
var connectTask = connectAsync.AsTask(cts.Token);

await connectTask;   

酷 - 这个方法对 await _socket.InputStream.ReadAsync 也适用吗? - DaveDev
我认为是这样的。所有属于“IAsyncAction”的内容都可以转换成任务1。但请确保创建一个新的“CancellationTokenSource”。 - esskar

3

由于我没有足够的声望来添加评论,所以我必须另外回答。

如果不需要额外变量,另一种方法是:

await socket.ConnectAsync(hostName, port).AsTask(new CancellationTokenSource(TimeSpan.FromSeconds(2)).Token);

这个不起作用,AsTask方法不存在(至少在.NET Core 3.0中不是)@Chris Ruck的方法可行。 - shelbypereira

1
我做了以下操作,对我来说似乎有效:

(保留HTML标签)

if (!_socket.ConnectAsync(uri, CancellationToken.None).Wait(timeout))
{
    // connect timed out
}

2
这种方法的问题在于它是阻塞的,而且你没有使用异步/等待的好处。我建议像这样做(参见:https://dev59.com/um855IYBdhLWcg3woVw_): int timeout = 1000; var task = SomeOperationAsync(); if (await Task.WhenAny(task, Task.Delay(timeout)) == task) { // 任务在超时之内完成 } else { // 超时逻辑 } - shelbypereira

1

我尝试使用esskar的答案/解决方案,但它并没有起作用,因为如先前提到的那样,在我使用的最新版本的.Net中不存在AsTask()方法。

因此,我稍微修改了解决方案来执行以下操作,请检查我的工作是否符合要求:

using (var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
      var timeout = 1000;
      var cts = new CancellationTokenSource();
      cts.CancelAfter(timeout);

      var connectAsync = sock.ConnectAsync(address, port, cts.Token); // address and port set earlier in scope
      await connectAsync;          
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接