Assume you have a server that waits for elements to arrive on a mpsc channel. Once an element arrives you serialize it and send it to a connected client:
let element = ch.recv().await.unwrap();
let buf = serialize(element);
frmio.send(buf).await.unwrap();
Now, assume a long time can pass between elements on channel so you want to detect EOF on frmio (a tokio-utilFramed) while waiting for data to arrive on the channel. What's the most conventional way to do that?
This works:
tokio::select!{
element = ch.recv().await => {
// ...
}
input => frmio.next() => {
// May be Some() or None, but doesn't matter which because
// no data is expected, and if data arrives at this point the client
// is in a bad state.
return
}
}
But semantically it feels weird to force a "fake" read just to detect an EOF. Is there some other way to do it?
I don't quite understand what is your problem. If you want to set a timeout on incoming messages and assume that if message timed out, then this is the end of your connection, then just use tokio::time::timeout. If you are implementing some protocol, which defines this kind of semantics, then it would help, if you would explain how it should work.
It's not a question about timeouts: When a client has connected to the server it requests to subscribe to a stream of messages. While the server is waiting for a message to arrive [from the internal mpsc channel] to forward to the client, it needs to detect if the client has disconnected.
I'll add some comments to the original code to better illustrate the problem
async fn handle_client_sub_conn(chrx: Receiver<Msg>, frmio: Framed<...>) {
loop {
// This blocks. If the client disconnects while we're waiting for
// for a message to arrive over the channel, then we won't notice
// it here.
let element = chrx.recv().await.unwrap();
let buf = serialize(element);
// It's not until we reach this point where we notice that the
// client has disconnected
frmio.send(buf).await.unwrap();
}
}
The question is simply: How can one detect that the client connection has been lost while waiting for a message to arrive over the mpsc channel. Does one need to attempt a fake read, or is there some other mechanism?
Note that if this client connection is a TCP connection, or something layered on top of it that doesn't implement any further liveness checking, then if the client has a communications or hardware failure (such that you don't receive a packet closing the connection), even the “fake read” won’t discover that the client is gone. The only way to confirm that a TCP connection is (not) dead is to try to send some data on it.
Therefore, if you need to ensure that your server cannot be cluttered with dead client connections, you need to actually send something periodically, at whatever interval you want to clean up. That might be all you need. On the other hand, if you want to discover the connection is closed more promptly under normal conditions, then you do need the “fake read”.