Timeout to cancel loop?

Clearly I am not understanding something correctly. How can I put a timer on a loop and have it cancel the loop?

I am trying to listen to a UDP socket for a period of time, then shut it down. But it doesn't seem to shut down. I've tried it without the spawn, with a timout on the spawn and now with an interval. Nothing seems to shut it down.

    // start time
    let start = tokio::time::Instant::now();
    // duration to check against
    let duration = tokio::time::Duration::new(5,0);
    // interval to wait on ticks
    let mut timer = tokio::time::interval(tokio::time::Duration::new(0,10));
    //spawn thread to do the work
    tokio::spawn(
        async move{
            loop{
                //await the timer interval to wake up the loop and check the time
                timer.tick().await;
                let now = tokio::time::Instant::now();
                println!("{:?}",now-start);
                // socket to listen on
                let sock = tokio::net::UdpSocket::bind(format!("0.0.0.0:{}",sock_add)).await;
                let mut buf = [0u8;1024];
                let b = r.recv_from(&mut buf).await.unwrap();
                println!("{:?} bytes received from:{:?}", &buf[0..b.0],b.1);
            }

In general, the two ways you can kill something when a timeout expires are:

  1. The tokio::time::timeout function.
  2. With a tokio::select!. (Where the other branch is a sleep or similar.)

You should not have to spawn a task.

This does not seem to work:

    tokio::time::timeout(tokio::time::Duration::new(5,0),
        async move{
            loop{
                let sock = tokio::net::UdpSocket::bind(format!("0.0.0.0:{}",10000)).await.unwrap();
                let mut buf = [0u8;1024];
                let b = r.recv_from(&mut buf).await.unwrap();
                println!("{:?} bytes received from:{:?}", &buf[0..a.0],a.1);
                }
          }
    }).await.unwrap();

What results are you seeing?

The loop just doesn't stop, so the program keeps running. I think the socket is still active, but haven't tested it.

Can you post a few lines of the output from the loop?

Besides, it doesn't make much sense to talk about the socket here. You keep creating new sockets.

The other option is that something else in your program is blocking the thread, preventing the runtime from switching back to your task when the timeout expires. To diagnose this, connect tokio-console to your application and look for tasks with a large number under the busy heading.

I had to heavily modify the code for posting. What's actually happening in my code is that I am sending an mDNS query and listening for responses. Since this is loop is just for for the responses to my message, I don't want to keep listening indefinitely.

It's ugly, but this is the actual loop that is running:

    tokio::time::timeout(tokio::time::Duration::new(5,0),async move{
            loop{
                let mut sock_add = 10000;
                let sock = tokio::net::UdpSocket::bind(format!("0.0.0.0:{}",sock_add)).await;
                match sock{
                    Ok(a)=>{
                        let r = Arc::new(a);
                        let s = r.clone();
                        tokio::spawn(async move {
                            loop{
                                let mut buf = [0u8;1024];
                                let b = r.recv_from(&mut buf).await;
                                match b{
                                    Ok(a)=>{
                                        println!("{:?} bytes received from:{:?}", &buf[0..a.0],a.1);
                                    },
                                    Err(e)=>{println!("{}",e)}
                                }
                            }
                        });
                        tokio::spawn(async move {
                            let mut msgbuild = dns::DnsMessageBuilder::new(dns::DnsMessageType::Query);
                            let msg = msgbuild.question(dns::DnsQuestion::new("_services._dns-sd._udp.local.".to_string(), false)).build();
                            let msg = msg.serialize();
                            let len = s.send_to(&msg, "224.0.0.251:5353").await;
                            match len{
                                Ok(a)=>{
                                    println!("bytes sent:{}",a);
                                },
                                Err(e)=>{println!("{}",e)}
                            };                            
                        });
                    },
                    Err(e)=>{
                        if sock_add<65500{
                            sock_add+=1;
                        }else{
                            println!("could not send mDNS: {}",e);
                            break
                        }
                    }
                }
            };
        }).await.unwrap();

Aha, in that case I think I know what the issue is. Cancelling the outer loop when the timeout triggers does not kill the tasks that you have spawned.

That was it. Timeout was in the wrong place, Thanks Alice!!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.