I would like to write async tcp client server. I wrote this code but a have a problem, when I call the disconnect method on client or stop method on server. I do not get an exception and I cannot determine that the client or the server is no longer available. How can I determine that the client or the server is no longer available?
Server
public class Server
{
    private readonly Dictionary<IPEndPoint, TcpClient> clients = new Dictionary<IPEndPoint, TcpClient>();
    private readonly List<CancellationTokenSource> cancellationTokens = new List<CancellationTokenSource>();
    private TcpListener tcpListener;
    private bool isStarted;
    public event Action<string> NewMessage;
    public async Task Start(int port)
    {
        this.tcpListener = TcpListener.Create(port);
        this.tcpListener.Start();
        this.isStarted = true;
        while (this.isStarted)
        {
            var tcpClient = await this.tcpListener.AcceptTcpClientAsync();
            var cts = new CancellationTokenSource();
            this.cancellationTokens.Add(cts);
            await Task.Factory.StartNew(() => this.Process(cts.Token, tcpClient), cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
        }
    }
    public void Stop()
    {
        this.isStarted = false;
        foreach (var cancellationTokenSource in this.cancellationTokens)
        {
            cancellationTokenSource.Cancel();
        }
        foreach (var tcpClient in this.clients.Values)
        {
            tcpClient.GetStream().Close();
            tcpClient.Close();
        }
        this.clients.Clear();
    }
    public async Task SendMessage(string message, IPEndPoint endPoint)
    {
        try
        {
            var tcpClient = this.clients[endPoint];
            await this.Send(tcpClient.GetStream(), Encoding.ASCII.GetBytes(message));
        }
        catch (Exception exception)
        {
        }
    }
    private async Task Process(CancellationToken cancellationToken, TcpClient tcpClient)
    {
        try
        {
            var stream = tcpClient.GetStream();
            this.clients.Add((IPEndPoint)tcpClient.Client.RemoteEndPoint, tcpClient);
            while (!cancellationToken.IsCancellationRequested)
            {
                var data = await this.Receive(stream);
                this.NewMessage.SafeInvoke(Encoding.ASCII.GetString(data));
            }
        }
        catch (Exception exception)
        {
        }
    }
    private async Task Send(NetworkStream stream, byte[] buf)
    {
        await stream.WriteAsync(BitConverter.GetBytes(buf.Length), 0, 4);
        await stream.WriteAsync(buf, 0, buf.Length);
    }
    private async Task<byte[]> Receive(NetworkStream stream)
    {
        var lengthBytes = new byte[4];
        await stream.ReadAsync(lengthBytes, 0, 4);
        var length = BitConverter.ToInt32(lengthBytes, 0);
        var buf = new byte[length];
        await stream.ReadAsync(buf, 0, buf.Length);
        return buf;
    }
}
Client
public class Client
{
    private TcpClient tcpClient;
    private NetworkStream stream;
    public event Action<string> NewMessage;
    public async void Connect(string host, int port)
    {
        try
        {
            this.tcpClient = new TcpClient();
            await this.tcpClient.ConnectAsync(host, port);
            this.stream = this.tcpClient.GetStream();
            this.Process();
        }
        catch (Exception exception)
        {
        }
    }
    public void Disconnect()
    {
        try
        {
            this.stream.Close();
            this.tcpClient.Close();
        }
        catch (Exception exception)
        {
        }
    }
    public async void SendMessage(string message)
    {
        try
        {
            await this.Send(Encoding.ASCII.GetBytes(message));
        }
        catch (Exception exception)
        {
        }
    }
    private async void Process()
    {
        try
        {
            while (true)
            {
                var data = await this.Receive();
                this.NewMessage.SafeInvoke(Encoding.ASCII.GetString(data));
            }
        }
        catch (Exception exception)
        {
        }
    }
    private async Task Send(byte[] buf)
    {
        await this.stream.WriteAsync(BitConverter.GetBytes(buf.Length), 0, 4);
        await this.stream.WriteAsync(buf, 0, buf.Length);
    }
    private async Task<byte[]> Receive()
    {
        var lengthBytes = new byte[4];
        await this.stream.ReadAsync(lengthBytes, 0, 4);
        var length = BitConverter.ToInt32(lengthBytes, 0);
        var buf = new byte[length];
        await this.stream.ReadAsync(buf, 0, buf.Length);
        return buf;
    }
}