Search code examples
c#async-awaittcpclient

Using Τask.Υield to allow socket tasks to run async


My question is when performing actions such as connecting to and receiving data from TCP sockets is Τask.Υield a suitable way to ensure these happen while allowing the main thread to continue?

In my example I have an automation code that can be connecting to 200 devices via TCP, and sometimes they may be offline resulting in longer timeouts. I want the main thread that called the connect method to continue on with other tasks while all these sockets connect.

public async Task<bool> Connect()
{
    await Task.Yield();
    _disconnected = false;
    _client = new TcpClient();
    try
    {
        _client.Connect(_ipAddress, _port);
        _failure = false;
        _stream = _client.GetStream();
        Connected?.Invoke(this, true);
        var ReceivingThread = new Thread(Receive);
        ReceivingThread.Start();
    }
    catch (Exception)
    {
        if (!_failure)
        {
            ErrorLog.Notice($"Failed to connect to {_ipAddress}");
        }
        _failure = true;
        _ = Connect();
    }
    return (!_failure);
}

Solution

  • Ended up with this after comments from Fildor. Test fantastic for 10 hours with 100 clients retrying every 1 second.

    public async Task<bool> Connect()
    {
        _client = new TcpClient();
        _disconnected = false;
        await Policy.Handle<Exception>(e => !_disconnected)
            .WaitAndRetryForeverAsync(_ => (TimeSpan.FromSeconds(1)), 
                (exception, waitDuration) => {
                    if (!_failure)
                    {
                        ErrorLog.Notice($"Failed to connect to 
                            {_ipAddress}");
                    }
                    _failure = true;
                })
                .ExecuteAndCaptureAsync(() => 
                    _client.ConnectAsync(_ipAddress, _port));
        if(!_disconnected)
        {
            _failure = false;
            _stream = _client.GetStream();
            Connected?.Invoke(this, true);
            Receive();
        }
        return !_failure;
    }