Making an async server in C# but StartAsync() giving me issues

87 Views Asked by At
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace MultipleClientAsyncServer
{
    class Program
    {
        private static void Main()
        {
            // Start the server on port 12345
            ListenForClients(12345);

            Console.ReadLine();
        }

        public static async void ListenForClients(int port)
        {
            using (var listener = new TcpListener(IPAddress.Loopback, port))
            {
                await listener.StartAsync();

                while (true)
                {
                    var client = await listener.AcceptTcpClientAsync();
                    
                    Console.WriteLine($"New client connected: {client.Client.RemoteEndPoint}");

                    // Create a new task for processing each client's messages asynchronously
                    Task.Run(() => ProcessClient(client));
                }
            }
        }
        
        private static async void ProcessClient(TcpClient tcpClient)
        {
            byte[] buffer = new byte[1024];
            NetworkStream stream;
            
            try
            {
                stream = tcpClient.GetStream();
                
                // Read a message from the client and display it on the server console
                while (true)
                {
                    await stream.ReadAsync(buffer, 0, buffer.Length);
                    string receivedMessage = Encoding.ASCII.GetString(buffer);
                    
                    Console.WriteLine($"Client: {tcpClient.Client.RemoteEndPoint} - Message: '{receivedMessage}'");
                }
            }
            catch (Exception)
            {
                // Client disconnected, clean up and close the stream
                tcpClient.Close();
                return;
            }
        }
    }
}

Error:

Error CS1061 'TcpListener' does not contain a definition for 'StartAsync' and no accessible extension method 'StartAsync' accepting a first argument of type 'TcpListener' could be found (are you missing a using directive or an assembly reference?)
MultipleClientAsyncServer C:\Users\cda4\Desktop\AI Projects\MultipleClientAsyncServer\Program.cs 23 Active

I generally have no idea whats happening here I swear you could use StartAsync() like this?

1

There are 1 best solutions below

0
matt sharp On

StartAsync() doesn't exist. If you want it to run then you have to use Start(). I think below may work as you intend:

 public class Listener
{
    public async Task ListenForClientsAsync(int port)
    {
        var listener = new TcpListener(IPAddress.Loopback, port);
        listener.Start(5);

        while (true)
        {
            var client = await listener.AcceptTcpClientAsync();

            Console.WriteLine($"New client connected: {client.Client.RemoteEndPoint}");

            // Create a new task for processing each client's messages asynchronously
            Task.Run(() => ProcessClientAsync(client));
        }
    }

    private async Task ProcessClientAsync(TcpClient tcpClient)
    {
        byte[] buffer = new byte[1024];

        try
        {
            using var stream = tcpClient.GetStream();

            // Read a message from the client and display it on the server console
            while (true)
            {
                while (!stream.DataAvailable);

                await stream.ReadAsync(buffer, 0, buffer.Length);
                string receivedMessage = Encoding.ASCII.GetString(buffer);

                Console.WriteLine($"Client: {tcpClient.Client.RemoteEndPoint} - Message: '{receivedMessage}'");
            }
        }
        catch (Exception)
        {
            // Client disconnected, clean up and close the stream
            tcpClient.Close();
            return;
        }
    }
}

In program.cs

await new Listener().ListenForClientsAsync(1234);

Changes:

  • TcpListener doesnt implement IDisposable so cant use "using"
  • Added using where applicable (handling of stream)
  • StartAsync doesnt work (no implementation, use .Start(max_connections)
  • return "Task" not void
  • I moved code to a class
  • Added "Async" to async method names so you know to await on use
  • Stopped read when data wasn't available (otherwise you get a loop of the same message)

Note: There's a bit of refactoring to be done too - up to you