Tokio program stuck

Hi, I try to play a bit with async program in rust and I run into a issue.

So first here short version from the code wich get stuck at some point:

extern crate futures;
extern crate tokio;

use futures::{channel::mpsc, StreamExt};
use std::io::Error;
use tokio::{
    net::{TcpListener, TcpStream},
    sync::watch,
};


type Result<T> = core::result::Result<T, Error>;
type Receiver<T> = mpsc::UnboundedReceiver<T>;
type Watcher<T> = tokio::sync::watch::Receiver<T>;

#[tokio::main]
async fn main() -> Result<()> {
    let addr = "127.0.0.1:50510".to_string();

    let (sender, reader) = mpsc::unbounded::<u8>();
    let (broadcaster, watcher) = watch::channel(0);

    other_loop(reader).await;
    accept_loop(addr, watcher).await
}

async fn other_loop(mut reader: Receiver<u8>) {
   tokio::spawn(async move {
      while let Some(_) = reader.next().await {}
   });
}

async fn accept_loop(
    addr: String,
    watcher: Watcher<u8>,
) -> Result<()> {
    let listener = TcpListener::bind(&addr).await?;
    let mut incoming = listener.incoming();
    println!("Listening on: {}", addr);
    while let Some(stream) = incoming.next().await {
        let stream = stream?;
        let receiver = watcher.clone();
        println!("Accepting from: {}", stream.peer_addr()?);
        tokio::spawn(async move {
            connection_loop(receiver, stream).await;
        });
    }
    Ok(())
}

async fn connection_loop(
    mut receiver: Watcher<u8>,
    stream: TcpStream,
) {
    while let Some(_) = receiver.recv().await {
    };
}

So I run it then some clients connect to the server and the first two are ok but then no more clients are accepted. On the real code I've a version where everything is ok just by putting code from other_loop directly into the main.
I don't understand what can go wrong so I hope someone can help me :grinning:

    other_loop(reader).await;
    accept_loop(addr, watcher).await
}

async fn other_loop(mut reader: Receiver<u8>) {
   tokio::spawn(async move {
      while let Some(_) = reader.next().await {}
   });
}

Can be rewritten as:

    other_loop(reader);
    accept_loop(addr, watcher).await
}

fn other_loop(mut reader: Receiver<u8>) {
   tokio::spawn(async move {
      while let Some(_) = reader.next().await {}
   });
}

Notice that other_loop doesn't have async and its call has no .await. That probably won't fix the issue though.

I don't know what the problem is though.

I ran the code and connected four times using telnet and it works fine for me?

Regarding the tokio spawns, you may be interested in this alternate syntax:

tokio::spawn(other_loop(reader));

async fn other_loop(mut reader: Receiver<u8>) {
    while let Some(_) = reader.next().await {}
}

Similarly:

tokio::spawn(connection_loop(receiver, stream));

In general, async move { function(args).await } is the same as function(args).

1 Like

Ok thanks both of you for syntaxic tips but I should precise that the multiple clients try to connect almost simultaneous.
I am able to reproduce the problem with a firefox where I spam "Ctrl + t", "Ctrl + v", "Enter" with the address ready to be paste ( Yeah not really nice way to create clients, but it work :sweat_smile: ).
The first X clients are accepted, then nothing.

Firefox has a limit to how many connections it will open at once to the same server. Try connecting from chrome once firefox stops connecting.

I come back with news, the code post here work fine :grinning: my issue was something else (and @alice you are right about firefox ).

I try different syntax base on examples that you give to me and removing my tokio::spawn(async move {}) from inside my function to put it outside just work.

The real code is bigger so I don't post it.

I still don't fully understand the problem but I will try to learn more about tokio task.

Thank you !

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.