That title is a little weird, but I have a UdpClient
and it uses ReceiveAsync
to listen for response from the remote endpoint after a SendAsync
. The problem is that the remote endpoint is a very flimsy IoT device that will either close the connection, or never reply.
I want to timeout the ReceiveAsync
so the socket can be released when the device decides to do nothing. I saw a genius comment by AJ Richardson here that suggests doing this:
Task.WhenAny(
client.ReceiveAsync(),
Task.Delay(5000)
);
I'm sure that works great, but if the ReceiveAsync
is successful, I need to read the response, but because it's wrapped in Task.WhenAny
, I have no idea how to do that.
Could anyone give me any suggestions? Thanks in advance!
Clarification
To clarify, here's my scenario. I have a Hangfire background job. It receives a data model and based on it sends a message to an IoT device using UDP. The problem is that the devices are flimsy and will not respond, which means the client will be awaiting forever.
If that happens then the client will be holding onto the port, and depending on how many times the job is queued I can eventually run out of ports since their clients are just stuck awaiting.
To avoid that, I want to timeout after a 5 second period and release the client's port and other resources. That is where Task.WhenAny
comes in. Either the ReceiveAsync
or Task.Delay
calls will complete first and end the process.
However, if ReceiveAsync
completes first, I need to capture the response from it and do further processing with it. How do I do that?
Here is a more complete code sample of what I'm working with.
var iotAddress = new IPAddress(iot.Ip);
var iotEndpoint = new IPEndPoint(iotAddress, iot.Port);
try {
using (var client = new UdpClient(0, AddressFamily.InterNetwork)) {
client.Connect(iotEndpoint);
await client.SendAsync(bytes, bytes.Length);
if (!iot.WaitForResponse) {
return;
}
// await the response of the IoT device
var response = await client.ReceiveAsync();
// OR
//
// await either the response of the IoT device,
// or the delay to complete, effectively creating
// a timeout.
var timeoutOrComplete = await Task.WhenAny(
client.ReceiveAsync(),
Task.Delay(5000)
);
// If a response was received before the "timeout"
// was triggered, how do I get it?
var response = timeoutOrComplete.???
}
} catch {
// Ignore
}