如何在 StreamSocket 的 ConnectAsync() 上设置超时值?

Posted

技术标签:

【中文标题】如何在 StreamSocket 的 ConnectAsync() 上设置超时值?【英文标题】:How to set a timeout value on StreamSocket's ConnectAsync()? 【发布时间】:2014-08-26 07:51:01 【问题描述】:

在 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() 设置超时时间吗?如果有,怎么做?

【问题讨论】:

【参考方案1】:

使用CancellationTokenSourceAsTask 扩展方法。

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 吗? 我会这么认为。所有属于“IAsyncAction”的东西都可以转换为任务 [1]。但请确保您创建了一个新的CancellationTokenSource。 [1]:msdn.microsoft.com/en-us/library/hh779334(v=vs.110).aspx【参考方案2】:

由于我没有添加评论的声誉,所以我不得不提出另一个答案。

另一种不需要额外变量的方式:

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

【讨论】:

这不起作用,@Chris Ruck 的 AsTask 方法不存在(至少在 .NET Core 3.0 中不存在)方法有效。【参考方案3】:

我执行以下操作,这似乎对我有用:

if (!_socket.ConnectAsync(uri, CancellationToken.None).Wait(timeout))

    // connect timed out

【讨论】:

这种方法的问题在于它是阻塞的,并且您使用 asnyc /await 的好处,我建议像(SEE:***.com/questions/4238345/…):int timeout = 1000; var 任务 = SomeOperationAsync(); if (await Task.WhenAny(task, Task.Delay(timeout)) == task) // 任务在超时时间内完成 else // 超时逻辑 【参考方案4】:

我尝试使用 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;          

【讨论】:

以上是关于如何在 StreamSocket 的 ConnectAsync() 上设置超时值?的主要内容,如果未能解决你的问题,请参考以下文章

使用 StreamSocket 升级到 SSL

UWP c# 从 StreamSocket 读取 XML

Windows8 Metro界面下的StreamSocket 发送数据与接收数据

Connecting to 172.16.128.14:22...Could not connec

学习笔记——mail发送javax.mail.AuthenticationFailedException: failed to connect at javax.mail.Service.connec

TCP 与 UDP 如何互通