Vusal Mastaliyev

Vusal Mastaliyev

  • NA
  • 30
  • 8.3k

C# Server and client project on Winform (Listing connected client's)

Mar 9 2023 8:34 PM

Below are my server codes.

    public class Networking
    {
        private readonly ILogger<Networking> logger;
        private readonly TcpListener listener;
        private readonly List<TcpClient> connectedClients = new List<TcpClient>();
        private bool isListening;


        public Networking(ILogger<Server> logger)
        {
            var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder.AddConsole();
            });

            this.logger = loggerFactory.CreateLogger<Networking>();
            listener = new TcpListener(IPAddress.Any, 333);
        }
        public async Task StartListeningAsync()
        {
            if (isListening)
            {
                return;
            }

            listener.Start();
            isListening = true;

            logger.LogInformation("Server started listening on {address}:{port}.", IPAddress.Any, 8080);

            while (isListening)
            {
                TcpClient client;

                try
                {
                    client = await listener.AcceptTcpClientAsync();
                }
                catch (ObjectDisposedException)
                {
                    break;
                }

                // Check if the same client is already connected from another computer
                foreach (TcpClient connectedClient in connectedClients)
                {
                    if (connectedClient.Client.RemoteEndPoint.ToString() == client.Client.RemoteEndPoint.ToString())
                    {
                        // If the same client is already connected, close the new connection and notify the client
                        byte[] response = Encoding.ASCII.GetBytes("You are already connected from another computer.");
                        NetworkStream stream = client.GetStream();
                        await stream.WriteAsync(response, 0, response.Length);
                        client.Close();

                        logger.LogWarning("Client {remoteEndPoint} attempted to connect, but is already connected from another computer.", client.Client.RemoteEndPoint);

                        continue;
                    }
                }

                connectedClients.Add(client);

                await HandleClientAsync(client);

                logger.LogInformation("Client {remoteEndPoint} connected.", client.Client.RemoteEndPoint);
            }
        }
        private async Task HandleClientAsync(TcpClient client)
        {
            try
            {
                using (NetworkStream stream = client.GetStream())
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                    string data = Encoding.ASCII.GetString(buffer, 0, bytesRead);

                    string[] credentials = data.Split(',');

                    if (IsUserValid(credentials[0], credentials[1]))
                    {
                        byte[] response = Encoding.ASCII.GetBytes("Success");
                        await stream.WriteAsync(response, 0, response.Length);

                        // Send a message to the client after successful connection
                        byte[] connectMsg = Encoding.ASCII.GetBytes("You have successfully connected to the server.");
                        await stream.WriteAsync(connectMsg, 0, connectMsg.Length);
                    }
                    else
                    {
                        byte[] response = Encoding.ASCII.GetBytes("Failure");
                        await stream.WriteAsync(response, 0, response.Length);
                    }
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Error handling client.");
            }
            finally
            {
                client.Close();
                connectedClients.Remove(client);
                logger.LogInformation("Server is shutting down.");
            }
        }
        private bool IsUserValid(string username, string password)
        {
            // Add database validation here
            return true;
        }
        public async Task StopServerAsync()
        {
            isListening = false;

            if (listener != null)
            {
                listener.Stop();
            }

            // Notify connected clients to disconnect
            byte[] disconnectMsg = Encoding.ASCII.GetBytes("Server is shutting down. Please disconnect.");
            foreach (TcpClient client in connectedClients)
            {
                try
                {
                    using (NetworkStream stream = client.GetStream())
                    {
                        await stream.WriteAsync(disconnectMsg, 0, disconnectMsg.Length);
                    }
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "Error sending disconnect message to client.");
                }
            }

            // Wait for 1 minute for clients to disconnect
            var timeout = TimeSpan.FromSeconds(60);
            var tasks = new List<Task>();
            foreach (TcpClient client in connectedClients)
            {
                tasks.Add(Task.Run(async () =>
                {
                    try
                    {
                        if (client.Connected)
                        {
                            using (NetworkStream stream = client.GetStream())
                            {
                                await stream.WriteAsync(disconnectMsg, 0, disconnectMsg.Length);
                                client.Close();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.LogError(ex, "Error sending disconnect message to client.");
                    }
                }));
            }
            await Task.WhenAll(tasks);
        }

        public async Task<List<string>> GetConnectedList()
        {
            List<string> connectedList = new List<string>();
            foreach (TcpClient connectedClient in connectedClients)
            {
                string clientName = connectedClient.Client.RemoteEndPoint.ToString();
                string clientIP = ((IPEndPoint)connectedClient.Client.RemoteEndPoint).Address.ToString();
                connectedList.Add(clientName + "|" + clientIP);
            }
            return connectedList;
        }
        private string GetUserName(TcpClient client)
        {
            // TODO: Implement code to retrieve the user name from the client
            // For example, you can send the user name to the server after a successful connection,
            // and store it in the connectedClients list along with the TcpClient instance.
            // Then you can retrieve it here using the TcpClient instance.
            return "Unknown";
        }
    }
    public partial class Server : Form
    {
        private readonly ILogger<Server> logger;
        private readonly Networking networking;

        public Server()
        {
            InitializeComponent();

            logger = LoggerFactory.Create(builder =>
            {
                builder.AddConsole();
            }).CreateLogger<Server>();

            networking = new Networking(logger);
        }

        private async void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                btnStart.Enabled = false;
                btnStop.Enabled = true;

                await networking.StartListeningAsync();
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Error starting server.");
            }
        }

        private async void btnStop_Click_1(object sender, EventArgs e)
        {
            try
            {
                btnStart.Enabled = true;
                btnStop.Enabled = false;


                await networking.StopServerAsync();
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Error stopping server.");
            }
        }

        private async void Server_Load(object sender, EventArgs e)
        {
            try
            {
                btnStart.Enabled = false;
                btnStop.Enabled = true;

                await networking.StartListeningAsync();
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Error starting server.");
            }
        }

        private async void Server_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                await networking.StopServerAsync();
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Error stopping server.");
            }
        }

        private async void btnGetConecctedList_Click(object sender, EventArgs e)
        {
            List<string> connectedList = await networking.GetConnectedList();
            foreach (string connectedClient in connectedList)
            {
                // Split the connected client information by '|'
                string[] info = connectedClient.Split('|');

                // Do something with the connected client
                string clientEndPoint = info[0] + " - " + info[1];
                lstClients.Items.Add(clientEndPoint);
            }
        }
    }

Below are my client codes.

namespace Client_Test
{
    public partial class Login : Form
    {
        public Login()
        {
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            string username = txtUsername.Text;
            string password = txtPassword.Text;

            using (TcpClient client = new TcpClient())
            {
                try
                {
                    await client.ConnectAsync("127.0.0.1", 333);
                    using (NetworkStream stream = client.GetStream())
                    {
                        byte[] buffer = Encoding.ASCII.GetBytes($"{username},{password}");
                        await stream.WriteAsync(buffer, 0, buffer.Length);

                        buffer = new byte[1024];
                        int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                        string response = Encoding.ASCII.GetString(buffer, 0, bytesRead);

                        if (response == "Success")
                        {
                            this.Hide();
                            MainForm mainForm = new MainForm();
                            mainForm.ShowDialog();
                            this.Close();
                        }
                        else
                        {
                            MessageBox.Show("Invalid username or password.");
                        }
                    }
                }
                catch (SocketException ex)
                {
                    if (ex.ErrorCode == 10061)
                    {
                        MessageBox.Show("Server is not running.");
                    }
                    else
                    {
                        MessageBox.Show($"Error connecting to server: {ex.Message}");
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"Error connecting to server: {ex.Message}");
                }
            }
        }
    }
}

The things I want to do are listed below in order.

1. Add User name and IP address in the list on the server side when each client is connected

2. If the server is down, when the client wants to connect, it will send a message that it is down

3. When I want to shut down the server while the clients are connected to the server, send a message to the clients "You need to exit the program, the server will be connected". If there is a client connected to the server, the server should watch for a change, then remove all the clients from the server and shut down the server.

4. While the server is removing the clients, a message is sent to the clients that they quit the program because the server was shut down.

5. Let me disconnect any user from the server if necessary


Answers (1)