static void Main(string[] args) { // Display logo ChatShell(); TcpListener listner = null; // The server will be listening to the below port for client connections int port = 6969; try { // Listen for client connections on any ip address on above declared port listner = new TcpListener(IPAddress.Any, port); listner.Start(); Console.WriteLine("ChatShell server started."); Console.WriteLine("Awaiting clients..."); // Run on an infinite loop while (true) { if (listner.Pending()) { TcpClient client = default(TcpClient); client = listner.AcceptTcpClient(); // Get username from client as a byte array and then encode to ASCII string; byte[] inStream = new byte[100]; NetworkStream networkStream = client.GetStream(); int bytesRead = networkStream.Read(inStream, 0, inStream.Length); string recievedData = Encoding.ASCII.GetString(inStream, 0, bytesRead); //Decrypt data gotten from client recievedData = encryptor.decrypt(recievedData); //Get connection password and username (stored in client data) string pass = recievedData.Substring(0, 4); string clientData = recievedData.Remove(0, 4); //If invalid connection password block user and send error message if (!pass.Equals("PASS")) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"Forceful connection declined!"); Console.ForegroundColor = ConsoleColor.White; // Send an encoded and encrypted message to the client saying that the username alredy exists byte[] outStream = Encoding.ASCII.GetBytes("Invalid client. Please use ChatShell to connect"); networkStream.Write(outStream, 0, outStream.Length); } // If user with the same username exists else if (clients.ContainsKey(clientData)) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"User with username {clientData} tried to connect. But was rejected as that username already exists"); Console.ForegroundColor = ConsoleColor.White; // Send an encoded and encrypted message to the client saying that the username alredy exists byte[] outStream = Encoding.ASCII.GetBytes(encryptor.encrypt("!error user-exists")); networkStream.Write(outStream, 0, outStream.Length); } else { // Send a message to the client allowing the connection after encryption. Encrypted message is turned into a bye array when sending byte[] outStream = Encoding.ASCII.GetBytes(encryptor.encrypt("!connect")); networkStream.Write(outStream, 0, outStream.Length); //Prevent network stream messages from overlapping Thread.Sleep(10); //Display message in server CLI Console.BackgroundColor = ConsoleColor.DarkGreen; Console.ForegroundColor = ConsoleColor.White; Console.WriteLine($"{clientData} connected to the chat"); Console.BackgroundColor = ConsoleColor.Black; //Broadcast message to other clients broadcastMessage($"!rc {clientData} connected to the chat", clientData, false); //Add new client to client list; clients.Add(clientData, client); // Send already connected user list to clients if (clients.Count != 0) { broadcastMessage(getUserList(), clientData, false); } //Create ClientClass object and set variable values ClientClass clientObject = new ClientClass(); clientObject.username = clientData; clientObject.client = client; //Create new thread to handle client Thread thread = new Thread(handleClient); thread.Start(clientObject); } } } }catch (Exception e) { Console.WriteLine(e.Message); } Console.ReadKey(); }
// Method to handle a single client (will run on multiple threads for different clients) static void handleClient(object clientObject) { // Cast the recieved ClientClass object ClientClass recievedClientObject = (ClientClass)clientObject; // Get the TcpClient object and username from the ClientClass object TcpClient client = recievedClientObject.client; string username = recievedClientObject.username; try { string dataFromClient = null; // Until client sends a disconnecting command run this loop do { // Recive data from the client using the network stream byte[] inStream = new byte[4096]; NetworkStream networkStream = client.GetStream(); int bytesRead = networkStream.Read(inStream, 0, inStream.Length); dataFromClient = Encoding.ASCII.GetString(inStream, 0, bytesRead); // Decrypt the data taken from client dataFromClient = encryptor.decrypt(dataFromClient); // If the client doesnt send a disconnect command if (!dataFromClient.Equals("!exit")) { // If the client wants to send a private message to another client if (dataFromClient.StartsWith("!pm")) { Console.WriteLine($"{dataFromClient}"); broadcastPrivateMessage(dataFromClient); } //If the client message is public else { Console.WriteLine($"{username}: {dataFromClient}"); broadcastMessage(dataFromClient, username, true); } } // Exit loop after client sends disconnect command } while (!(dataFromClient.Equals("!exit") || dataFromClient == null)); // After the client had disconnected // Remove the client from the hashtable clients.Remove(username); // Display message on server Console.BackgroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.White; Console.WriteLine($"{username} disconnected from the chat"); Console.BackgroundColor = ConsoleColor.Black; // Broadcast to other clients in an encoded message that the client has disconnected broadcastMessage($"!dc {username} disconnected from the chat", username, false); // Send updated user list to clients if there are connected clients if (clients.Count != 0) { broadcastMessage(getUserList(), username, false); } } catch (IOException e) { Console.WriteLine(e.Message); } finally { // Finally close the created TcpClient object if (client != null) { client.Close(); } } }