Now that we have initialized the network settings we can create an instance of the p2p network.

We will next create a Dchat struct that will store all the data required by dchat. For now, it will just hold a pointer to the p2p network.

struct Dchat {
    p2p: net::P2pPtr,

impl Dchat {
    fn new(
        p2p: net::P2pPtr,
    ) -> Self {
        Self { p2p }

Let's build out our realmain function as follows:

use log::info;

async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
    let p2p = net::P2p::new(, ex.clone()).await;
    info!("Starting P2P network");

    let (signals_handler, signals_task) = SignalHandler::new(ex)?;
    info!("Caught termination signal, cleaning up and exiting...");

    info!("Stopping P2P network");


Here, we instantiate the p2p network using P2p::new. We then start it by calling start, and handle shutdown signals to safely shutdown the network using P2p::stop.

Let's take a quick look at the underlying p2p methods we're using here.


This is start:

/// Starts inbound, outbound, and manual sessions.
pub async fn start(self: Arc<Self>) -> Result<()> {
    debug!(target: "net::p2p::start()", "P2P::start() [BEGIN]");
    info!(target: "net::p2p::start()", "[P2P] Starting P2P subsystem");

    // First attempt any set manual connections
    for peer in &self.settings.peers {

    // Start the inbound session
    if let Err(err) = self.session_inbound().start().await {
        error!(target: "net::p2p::start()", "Failed to start inbound session!: {}", err);
        return Err(err)

    // Start the outbound session

    info!(target: "net::p2p::start()", "[P2P] P2P subsystem started");

start attempts to start an Inbound, Manual or Outbound session, which will succeed or fail depending on how your TOML is configured. For example, if you are an outbound node, session_inbound.start() will return with the following message:

info!(target: "net", "Not configured for accepting incoming connections.");

The function calls in start trigger the following processes:

session_manual.connect: tries to connect to any peer addresses we have specified in the TOML, using a Connector.

session_inbound.start: starts an Acceptor on the inbound address specified in the TOML, then creates and registers a Channel on that address.

session_outbound.start: tries to establish a connection using a Connector to the number of slots we have specified in the TOML field outbound_connections. For every Slot, run tries to find a valid address we can connect to through PeerDiscovery, which loops through all connected channels and sends out a GetAddr message. If we don't have any connected channels, run performs a SeedSync.


This is stop.

/// Stop the running P2P subsystem
pub async fn stop(&self) {
    // Stop the sessions

stop transmits a shutdown signal to all channels subscribed to the stop signal and safely shuts down the network.