#Networking with Tokio

2 messages · Page 1 of 1 (latest)

teal flame
#

I am trying to make a small networking app with tokio, right now I am working on a sort of lobby. Players in this lobby are able to ready/unready, and people can join this lobby anytime. I have been trying to spawn a task that will send ready/unready requests to the server while listening to player join messages from the server, but getting this all to work nicely. My code looks something like this.

let local_addr = "0.0.0.0:0".parse::<SocketAddr>().unwrap();
let server_addr = "127.0.0.1:800".parse::<SocketAddr>().unwrap();
let socket = UdpSocket.bind(local_addr).await?;

let ready_request_task = tokio::task::spawn( async move {
  let socket = UdpSocket.bind(local_addr).await?;
  
  loop {
    let ready_status = PromptUserForBoolInput();
    socket.connect(server_addr);
    socket.send(&ready_status).await;
  }
});

let mut players = Vec::new();
loop {
  game.draw_ui();
  let server_message = socket.udp_socket.recv(&mut data).await?;
  
  match server_message {
    PlayerJoinedLobby(player) => {
      players.push(player);
      continue;
    }
    GameStart => { 
      ready_request_task.abort();
      break; 
  }

  // more code that uses socket
}

This code does not work as I am moving the socket from the main thread into the task, but the main thread still needs the socket. I can't just have two sockets and use on for the main thread and the other for the task because on the server side I need each client to use one only socket and only that socket for the whole program.

How can I get this sort of asynchronous networking with tokio?

arctic sage
#
  1. consider using the actor approach from https://ryhl.io/blog/actors-with-tokio/ (watch the related vid too it's GOAT-tier). There's also a related Telnet protocol implementation on Alice's github.
  2. If you're not wedded to doing UDP for this, consider using iroh. It's got some really nice patterns for connection and some great youtube vids for getting a good overview

To your question - from the docs:

This type does not provide a split method, because this functionality can be achieved by instead wrapping the socket in an Arc. Note that you do not need a Mutex to share the UdpSocket — an Arc<UdpSocket> is enough. This is because all of the methods take &self instead of &mut self. Once you have wrapped it in an Arc, you can call .clone() on the Arc<UdpSocket> to get multiple shared handles to the same socket. An example of such usage can be found further down.