/// <summary> /// When a tcpClient is accepted, we set up a new ChatConnection /// and use that for stream read/ write. The ChatConnection is then set to start listening to. /// At the end, the server is set to accept further tcpClient. /// </summary> /// <param name="ar"></param> private void AcceptCallback(IAsyncResult ar) { var server = (TcpListener)ar.AsyncState; try { var client = server.EndAcceptTcpClient(ar); var connection = new ChatConnection(client) { EndPoint = client.Client.RemoteEndPoint.ToString() }; connections.Add(connection); var evMsg = "connection from " + connection.EndPoint; ShowAndLog(LogLevel.Info, evMsg); connection.BeginRead(ReadCallback, connection); // Set server to accept client mode. server.BeginAcceptTcpClient(AcceptCallback, server); } catch (Exception ex) { Console.WriteLine("In AcceptCallback: " + ex); } }
/// <summary> /// Disconnecting a certain connection when the associated client (user) is leaving. /// This event is logged. /// </summary> /// <param name="disconnecting"></param> private void Disconnect(ChatConnection disconnecting) { lock (connections) { connections.Remove(disconnecting); } disconnecting.CloseConnection(); var msg = $"{disconnecting.UserName} left"; ShowAndLog(LogLevel.Info, msg); }
/// <summary> /// When connected to the server, create a ChatConnection to handle read/write to stream. /// Start to listen for messages from server with BeginRead. /// At last, send the current user name to the server for update. /// </summary> /// <param name="ar"></param> private void ConnectCallback(IAsyncResult ar) { try { var client = (TcpClient)ar.AsyncState; client.EndConnect(ar); Connection = new ChatConnection(client) { UserName = ClientName }; Connection.BeginRead(ReadCallback, Connection); Connection.BeginWrite(WriteCallback, Connection, $"/r {ClientName}"); } catch (Exception ex) { Console.WriteLine("In ConnectCallback: " + ex); } }
/// <summary> /// Can handle disconnect of client ("/q"), /// can handle rename of user name ("/r"), /// can handle user names request ("/u"), /// can handle whisper from one user to another ("/w"), and /// can handle send message to all ("/a"). /// </summary> /// <param name="message"></param> /// <param name="sender"></param> private void ParseMessage(string message, ChatConnection sender) { var lines = message.Split(' ').ToList(); var command = lines[0].ToLowerInvariant(); if (command.Equals("/q")) { Disconnect(sender); var msg = $"/i {GetUsernamesAsString()}"; lock (connections) { foreach (var connection in connections) { connection.BeginWrite(WriteCallback, connection, msg); } } } else if (command.Equals("/r")) { if (lines.Count == 2) { sender.UserName = lines[1]; var evMsg = $"{sender.EndPoint} renamed to {sender.UserName}"; ShowAndLog(LogLevel.Info, evMsg); var msg = $"/i {GetUsernamesAsString()}"; lock (connections) { foreach (var connection in connections) { connection.BeginWrite(WriteCallback, connection, evMsg); } } } } else if (command.Equals("/u")) { var msg = $"{sender.UserName} ask for usernames"; ShowAndLog(LogLevel.Info, msg); sender.BeginWrite(WriteCallback, sender, $"/i {GetUsernamesAsString()}"); } else if (command.Equals("/w")) { if (lines.Count > 2) { var msg = string.Join(" ", lines.GetRange(2, lines.Count - 2)); var receiver = connections.FirstOrDefault(c => c.UserName == lines[1]); if (receiver != null && sender.UserName != receiver.UserName) { var evMsg = $"{sender.UserName}->{receiver.UserName}:{msg}"; ShowAndLog(LogLevel.Info, evMsg); receiver.BeginWrite(WriteCallback, receiver, $"{sender.UserName}:{msg}"); sender.BeginWrite(WriteCallback, sender, $"+ {message}"); return; } } sender.BeginWrite(WriteCallback, sender, $"- {message}"); } else if (command.Equals("/a")) { if (lines.Count > 1) { var msg = string.Join(" ", lines.GetRange(1, lines.Count - 1)); var evMsg = $"{sender.UserName}->all:{msg}"; ShowAndLog(LogLevel.Info, evMsg); msg = sender.UserName + ":" + string.Join(" ", lines.GetRange(1, lines.Count - 1)); foreach (var connection in connections) { if (connection.UserName != sender.UserName) { connection.BeginWrite(WriteCallback, connection, msg); } } sender.BeginWrite(WriteCallback, sender, $"+ {message}"); return; } sender.BeginWrite(WriteCallback, sender, $"- {message}"); } }