I have a TcpListener server that can open a connection with a client by calling server.AcceptTcpClientAsync(). Unfortunately, there is random, unwanted traffic connecting to the server that I don't care about, so I've added a method, Task<bool> Handshake(TcpClient client), to validate that the client should be able to talk to the server.
The naive way to get a connection is:
async Task<TcpClient> GetClient(TcpListener server)
{
while (true)
{
var client = await server.AcceptTcpClientAsync();
if (await Handshake(client))
{
return client;
}
client.Dispose();
}
}
Unfortunately, the handshake process takes a nonzero amount of time to timeout when waiting on a spurious connection, and if it takes longer than it takes for the next connection to show up, pending connections will stack up and never get serviced.
I know that APIs like Task.WhenAny allow for multiple async operations to be running at once, but I can't seem to get a proper model for this connection process worked out.
What I want:
- Only one successful connection is expected.
- When a connection arrives, attempt a handshake. If the handshake is successful, return it and dispose any other pending connections. If not, dispose the connection.
- A handshake being in progress should not prevent the loop from accepting a new connection.
- It's always possible for the number of handshakes in progress to be 0, 1, or more than 1.
Is there any good way to express this in code?