CODESAMPLE

Peer-to-Peer - C#

Share on:

The Peer-to-Peer (P2P) pattern establishes direct communication and data exchange between independent components (peers) without relying on a central server. Each peer acts as both a client and a server, discovering and connecting to other peers. This example utilizes .NET’s built-in TCP networking capabilities to simulate a simple P2P chat application. Each peer listens for incoming connections and can initiate connections to other peers. Messages are sent directly between connected peers. This implementation is idiomatic C# due to its use of async/await for non-blocking network operations, using statements for resource management, and clear class structure representing peer functionality.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

public class Peer
{
    private readonly int _port;
    private readonly string _name;
    private TcpListener _listener;
    private bool _isRunning = false;

    public Peer(int port, string name)
    {
        _port = port;
        _name = name;
    }

    public async Task Start()
    {
        _listener = new TcpListener(IPAddress.Any, _port);
        _listener.Start();
        _isRunning = true;

        Console.WriteLine($"Peer {_name} started on port {_port}");

        while (_isRunning)
        {
            TcpClient client = await _listener.AcceptTcpClientAsync();
            _ = HandleClientAsync(client); //Fire and forget
        }
    }

    public async Task ConnectToPeerAsync(string ipAddress, int port)
    {
        try
        {
            TcpClient client = new TcpClient();
            await client.ConnectAsync(IPAddress.Parse(ipAddress), port);
            _ = HandleClientAsync(client);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Failed to connect to {ipAddress}:{port} - {ex.Message}");
        }
    }


    private async Task HandleClientAsync(TcpClient client)
    {
        using (client)
        using (NetworkStream stream = client.GetStream())
        {
            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
            {
                string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"Received from {client.Client.RemoteEndPoint}: {message}");
            }
        }
        Console.WriteLine("Client disconnected");
    }

    public async Task SendMessageAsync(string message, TcpClient client)
    {
        if (client.Connected)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(message);
            NetworkStream stream = client.GetStream();
            await stream.WriteAsync(buffer, 0, buffer.Length);
            await stream.FlushAsync();
        }
        else {
            Console.WriteLine("Client not connected. Message not sent.");
        }
    }

    public void Stop()
    {
        _isRunning = false;
        _listener.Stop();
        Console.WriteLine($"Peer {_name} stopped.");
    }
}

public class Program
{
    public static async Task Main(string[] args)
    {
        Peer peer1 = new Peer(12345, "Peer 1");
        Peer peer2 = new Peer(12346, "Peer 2");

        Task startPeer1 = peer1.Start();
        Task startPeer2 = peer2.Start();

        //Connect Peer 2 to Peer 1
        await peer2.ConnectToPeerAsync("127.0.0.1", 12345);

        Console.WriteLine("Press any key to stop...");
        Console.ReadKey();

        peer1.Stop();
        peer2.Stop();
    }
}