0

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;
    }
}
Alex808
  • 101
  • 6
  • 1
    Note, that the first answer of the linked duplicate is incorrect. The second one telling you that it is not possible to know is correct. – usr Apr 12 '15 at 16:53
  • Can you not just check to see if you receive 0 bytes? That's usually how a client/server will disconnect - the socket flushes null repeatedly. – user1274820 Apr 12 '15 at 16:55

0 Answers0