How it works...

This recipe doesn't introduce any new modules or concepts. It's here to provide you with a general idea of how to combine all the things you've learned in this recipe in a somewhat realistic context. Specifically, our context consists of code that manages clients that connect with us in some way.

Client [8] holds all information relevant to a connection. As a basic example, it currently contains the client's IP address. Other possibilities would be the client's username, location, device, ping, and so on.

The ConnectionHandler [14] itself holds a list, more specifically a HashMap, of the active connections, indexed by a unique ID. Analogous to that, it also stores the ID for the next connection.

We are using unique IDs instead of a Vec<Client> because clients might be able to connect, multiple times, to whatever service we are providing on the same device. The easiest example for this is multiple tabs open in a browser, all accessing the same website. Generally speaking, it is good practice to always hold your data behind unique keys to save yourself from trouble down the road.

The implementations of the structs should be straightforward. Methods that need to modify the clients member lock it with .write(), all others with .read().

The code used to get a new ID at add_connection adds one to next_id and returns its last value, as usual for an atomic[42]:

let last = self.next_id.fetch_add(1, Ordering::SeqCst);

After adding the connection to the clients, we return the newly-acquired ID to the caller, so that they can store the ID however they want and reuse it when it's time to kick the client with remove_connection [50], which in turn returns an Option telling the caller if the removed ID was in the client list in the first place. We do not return the removed Client directly because that would reveal unnecessary implementation details to the user of ConnectionHandler.

The code in main simulates parallel access to the hypothetical service. A bunch of clients connect to our ConnectionHandler and some leave again. thread::sleep [70, 80 and 90] blocks the current thread for a specified time and is used here to simulate the effect of various events happening at irregular intervals, represented by the different waiting times for each task.

As with the RwLock example, this program will have very different output every time you run it, so try it out multiple times.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.235.144