using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Xml.Serialization; namespace MainServer { public partial class Form1 : Form { //TcpListener listens for incoming TCP requests on port 5000 TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 5000); TcpClient client; //manage the incoming client requests String clNo; //store the client number Dictionary clientList = new Dictionary(); // keep track of all clients CancellationTokenSource cancellation = new CancellationTokenSource(); //List object to store the chat messages List chat = new List(); public Form1() { InitializeComponent(); } private void btnStart_Click(object sender, EventArgs e) { //Resets the cancellation token when the server restarts cancellation = new CancellationTokenSource(); startServer(); } public void updateUI(String m) { // update textbox with the received data this.Invoke((MethodInvoker)delegate { textBox1.AppendText("-" + m + Environment.NewLine); }); } public async void startServer() { //Starts the TCP listener listener.Start(); //Updates the UI showing server has started updateUI("Server Started at " + listener.LocalEndpoint); //Updates UI showing server is waiting for clients updateUI("Waiting for Clients"); try { int counter = 0; while (true) { counter++; //Accepts incoming TCP connection client = await Task.Run(() => listener.AcceptTcpClientAsync(), cancellation.Token); //Reads username byte[] name = new byte[50]; NetworkStream stre = client.GetStream(); stre.Read(name, 0, name.Length); String username = Encoding.ASCII.GetString(name); username = username.Substring(0, username.IndexOf("$")); clientList.Add(username, client); //Adds the client to the dictionary listBox1.Items.Add(username); //Adds the username to the listbox updateUI("Connected to user " + username + " - " + client.Client.RemoteEndPoint); // indicate client has connected announce(username + " Joined ", username, false); //Sends message to clients that a user has joined //Delays the task by 1 second, then sends the list of users to clients await Task.Delay(1000).ContinueWith(t => sendUsersList()); //Starts new thread to receive data from client var c = new Thread(() => ServerReceive(client, username)); c.Start(); } } catch (Exception) { //Stops the TCP listener if theres an exception listener.Stop(); } } // broadcasts a message to all connected clients. public void announce(string msg, string uName, bool flag) { try { foreach (var Item in clientList) { TcpClient broadcastSocket; broadcastSocket = (TcpClient)Item.Value; NetworkStream broadcastStream = broadcastSocket.GetStream(); Byte[] broadcastBytes = null; if (flag) { // message with the username and message chat.Add("gChat"); chat.Add(uName + " says : " + msg); broadcastBytes = ObjectToByteArray(chat); } else { // message with the message content only chat.Add("gChat"); chat.Add(msg); broadcastBytes = ObjectToByteArray(chat); } // Send message to client broadcastStream.Write(broadcastBytes, 0, broadcastBytes.Length); broadcastStream.Flush(); // Clear chat list for next message chat.Clear(); } } catch (Exception er) { // Catch any exceptions } } // converts a byte array to an object. public Object ByteArrayToObject(byte[] arrBytes) { using (var memStream = new MemoryStream()) { var binForm = new BinaryFormatter(); memStream.Write(arrBytes, 0, arrBytes.Length); memStream.Seek(0, SeekOrigin.Begin); var obj = binForm.Deserialize(memStream); return obj; } } // converts an object to a byte array. public byte[] ObjectToByteArray(Object obj) { BinaryFormatter bf = new BinaryFormatter(); using (var ms = new MemoryStream()) { bf.Serialize(ms, obj); return ms.ToArray(); } } // handles receiving messages from client. public void ServerReceive(TcpClient clientn, String username) { byte[] data = new byte[1000]; String text = null; // receive messages until the connection is closed --loop while (true) { try { // Get network stream for the client NetworkStream stream = clientn.GetStream(); // Read message from client stream.Read(data, 0, data.Length); // Convert message from a byte array to a list of strings List parts = (List)ByteArrayToObject(data); // Check the first part of the message switch (parts[0]) { case "gChat": // Display message in text box on the server form this.Invoke((MethodInvoker)delegate { textBox1.Text += username + ": " + parts[1] + Environment.NewLine; }); // Broadcast message to all clients announce(parts[1], username, true); break; } // Clear parts list for next message parts.Clear(); } catch (Exception r) { updateUI("Client Disconnected: " + username); announce("Client Disconnected: " + username + "$", username, false); clientList.Remove(username); // removes the username from the list box this.Invoke((MethodInvoker)delegate { listBox1.Items.Remove(username); }); // Send updated user list to clients sendUsersList(); // Exit the method break; } } } private void btnServerStop_Click(object sender, EventArgs e) { try { listener.Stop(); updateUI("Server Stopped"); // Close all client connections foreach (var Item in clientList) { TcpClient broadcastSocket; broadcastSocket = (TcpClient)Item.Value; broadcastSocket.Close(); } } catch (SocketException er) { } } private void disconnectToolStripMenuItem_Click(object sender, EventArgs e) { try { TcpClient workerSocket = null; // Get selected client's username from the list box String clientName = listBox1.GetItemText(listBox1.SelectedItem); // Find client in the dictionary using username workerSocket = (TcpClient)clientList.FirstOrDefault(x => x.Key == clientName).Value; // Close client connection workerSocket.Close(); } catch (SocketException se) { } } public void sendUsersList() { try { byte[] userList = new byte[1024]; // byte array to store user list data string[] clist = listBox1.Items.OfType().ToArray(); // string array of current clients in the listBox control List users = new List(); // List to store user data // Add 'userList' to List users.Add("userList"); // add all clients to list foreach (String name in clist) { users.Add(name); } // Convert List to byte array userList = ObjectToByteArray(users); // Send byte array to all clients in the clientList foreach (var Item in clientList) { TcpClient broadcastSocket; broadcastSocket = (TcpClient)Item.Value; // Retrieve the TcpClient object from the dictionary NetworkStream broadcastStream = broadcastSocket.GetStream(); // Retrieve the NetworkStream from the TcpClient object broadcastStream.Write(userList, 0, userList.Length); // Send the byte array to the client broadcastStream.Flush(); // Flush stream to ensure the data is sent immediately users.Clear(); // Clear the List for the next iteration } } catch (SocketException se) { } } private void textBox1_TextChanged(object sender, EventArgs e) { // scroll to the bottom of the textbox whenever text changes textBox1.SelectionStart = textBox1.TextLength; textBox1.ScrollToCaret(); } private void textBox1_TextChanged_1(object sender, EventArgs e) { } } }