6

In the Windows Phone 8.1 app I had to create my socket as follows. How can I change it so that it will timeout after a period that I can specify?

_socket = new StreamSocket();
await _socket.ConnectAsync(hostName, port.ToString(), SocketProtectionLevel.PlainSocket);

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

In my pre- Windows Phone code I'd create the Socket and set the timeout by testing _event.WaitOne(timeout), e.g.

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;
}

Can I set the timeout period for StreamSocket's ConnectAsync()? If so, how?

luksch
  • 11,497
  • 6
  • 38
  • 53
DaveDev
  • 41,155
  • 72
  • 223
  • 385

4 Answers4

8

Use a CancellationTokenSource and AsTask extension method.

var cts = new CancellationTokenSource();
cts.CancelAfter(2000); // cancel after 2 seconds

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

await connectTask;   
esskar
  • 10,638
  • 3
  • 36
  • 57
  • cool - would this work with `await _socket.InputStream.ReadAsync` also? – DaveDev Aug 26 '14 at 08:10
  • i would think so. Everything that is a 'IAsyncAction` can be converted to a task [1]. But make sure you create a new `CancellationTokenSource`. [1]: http://msdn.microsoft.com/en-us/library/hh779334(v=vs.110).aspx – esskar Aug 26 '14 at 08:17
2

Since I do not have the reputation to add a comment I have to put it another answer.

Another way that doesn't require extra variables if they aren't required:

await socket.ConnectAsync(hostName, port).AsTask(new CancellationTokenSource(TimeSpan.FromSeconds(2)).Token);
Michael Woolsey
  • 803
  • 8
  • 15
1

I do the following, which seems to work for me:

if (!_socket.ConnectAsync(uri, CancellationToken.None).Wait(timeout))
{
    // connect timed out
}
Chris Ruck
  • 391
  • 3
  • 4
  • 2
    the issue with this approach is that it is blocking, and you use the asnyc /await benefits, I would suggest something like (SEE: https://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout): int timeout = 1000; var task = SomeOperationAsync(); if (await Task.WhenAny(task, Task.Delay(timeout)) == task) { // task completed within timeout } else { // timeout logic } – shelbypereira Jan 28 '20 at 07:34
0

I tried using esskar's answer/solution but it didn't work since, as has been previously mentioned, the AsTask() method doesn't exist in latest version of .Net that I'm using.

So, I tweaked the solution just a tad to do the following, please check my work to see if this meets the requirements:

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;          
}