Quinn questions that may not be Quinn related: 100%cpu, won't send unless listening

I am trying to figure out how to run Quinn at a very basic level before trying to go any further.
I finally have something that works after a lot of headpounding and digging around due to nuances in rustls and such. I did search for answers, but I'm not particularly good at that. If there is a resource I missed and should have looked at before posting, I will be happy to look at it if you point me in the right direction.

Code is pasted at the bottom. The questions glaring for me are:

  1. When I run it and I run top on Linux it shows a cpu at 100. This seems to be related to the loop for the listener spawned. Is this normal? It certainly seems like it shouldn't be and I am thinking there must be a detail I'm missing that would prevent that.

  2. If the client doesn't have the listening loop, the sendstream does not seem to be sent and the connection is immediately closed. This seems strange to me since the listening loop isn't started until the message should have already been send and finished.

Comments welcome on any of the code below!!
I know there are a lot of unwraps, I handle errors after I have it working. I know it's a bad practice
Also, I am intending on doing mTLS which is why they are both servers, but the client has client config.

[tokio::main]
async fn main()->Result<(),Box<dyn std::error::Error>> {
    let client_cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()]).unwrap();
    let server_cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()]).unwrap();
    let c = client_cert.cert.der().to_owned().clone();
    let s = server_cert.cert.der().to_owned().clone();
    let mut roots = RootCertStore::empty();
        roots.add(CertificateDer::from(client_cert.cert)).unwrap();
        roots.add(CertificateDer::from(server_cert.cert)).unwrap();
    let roots = Arc::new(roots);
    let roots_clone = roots.clone();
    let server = tokio::spawn(
        async move {
        let roots = Arc::clone(&roots);
        let server_addr = "127.0.0.1:7897".parse::<SocketAddr>().unwrap();
        let cert_der = s;
        let key = PrivatePkcs8KeyDer::from(server_cert.key_pair.serialize_der());
        let config = ServerConfig::with_single_cert(vec![cert_der], key.into()).unwrap();
        let endpoint = Endpoint::server(config, server_addr).unwrap();
        let (mut s,mut r)= match endpoint.accept().await{
            Some(a)=>{
                match a.await{
                    Ok(a)=>{
                        match a.accept_bi().await{
                            Ok(mut a)=>{
                                a},
                            Err(e)=>{
                                panic!("stream error: {e}")}
                        }},
                    Err(e)=>{panic!("connection error: {e}")}
                }
            },
            None=>{panic!("accept server: panic on accept");}
        };
            
        let rx_handle = tokio::spawn(async move {
            let data = r.read_to_end(128).await.unwrap();
            println!("{}", String::from_utf8(data).unwrap());
        });
        rx_handle.await.unwrap();
    });
    let client = tokio::spawn(async move {
        let roots=Arc::clone(&roots_clone);
        static SERVER_NAME: &str = "localhost";
        let server_addr = "127.0.0.1:7899".parse::<SocketAddr>().unwrap();
        let cert_der = CertificateDer::from(c);
        let cder = cert_der.clone();
        let key = PrivatePkcs8KeyDer::from(client_cert.key_pair.serialize_der());
        let config = ServerConfig::with_single_cert(vec![cert_der], key.clone_key().into()).unwrap();
        let mut endpoint = Endpoint::server(config, server_addr).unwrap();     
        let q_client = client_config(key.clone_key(), cder.clone(),roots).unwrap();
        endpoint.set_default_client_config(q_client);
        let c = endpoint.connect("127.0.0.1:7897".parse().unwrap(), "localhost");
        match c{
            Ok(mut a)=>{
                //println!("data: {:?}",a.clone().await);
                let (mut s,mut r) = match a.await{
                    Ok(b)=>{b.open_bi().await.unwrap()},
                    Err(e)=>{panic!("{e}")}
                };
                let _wr = s.write_all(b"testing").await.unwrap();
                let _wr_f = s.finish().unwrap();
                let listening = tokio::spawn(async move{
                    loop{
                        let mut buf:Vec<u8> =Vec::new();
                        r.read(&mut buf).await;
                        if !buf.is_empty(){println!("{:?}",buf);}
                    }
                });
                listening.await;            
                },
            Err(e)=>{println!("{e}")}
        }      
    });
    let _ = client.await;
    let _ = server.await;
    Ok(())
}

pub fn client_config(key: PrivatePkcs8KeyDer<'static>, cert: CertificateDer<'static>,roots: Arc<RootCertStore>)->anyhow::Result<ClientConfig>{
    let builder = rustls::ClientConfig::builder_with_provider(rustls::crypto::ring::default_provider().into())
        .with_protocol_versions(&[&rustls::version::TLS13])
        .unwrap();
    let roots = roots.clone();
    let r_config = builder.with_root_certificates(roots).with_client_auth_cert(vec![cert], key.clone_key().into()).unwrap();
    let config = quinn::crypto::rustls::QuicClientConfig::try_from(r_config).unwrap();
    Ok(quinn::ClientConfig::new(Arc::new(config)))
}

No need to apologize; in fact, you have several matches that really should be written as unwraps — or rather, .expect()s, which lets you write a message to include. This will be equivalent but much shorter, and easier to revise.

I don't see where your 100% CPU usage is coming from, but your first debugging step should be to use a sampling profiler to find out which code is using the CPU.

Are you running the client and server on the same computer? If so, you're likely using the loopback network interface, in which case transferring data is CPU-bound (encryption mostly) because there's no network layer limiting the performance like there would be if it were actually two separate computers.

I am, but there's only one message passed and while it's an open connection, what's being encrypted? It seems more likely that the loop constantly attempting to read the empty buffer is doing it. Not sure the right way to handle that listener though. I'll have to keep thinking.