/// <summary> /// Take the incoming data from a client and convert it into a TFMS_Data object /// </summary> /// <param name="socket">the socket that connects the server and the client</param> /// <param name="info">the information about the client from the socket</param> /// <param name="result">the result of the connection attempt</param> /// <returns></returns> private TFMS_Data extractData(Socket socket, TFMS_ClientInfo info, IAsyncResult result) { try { int numBytesReceived = socket.EndReceive(result); // EndReceive returns how many bytes were received byte[] temp = new byte[numBytesReceived]; // the buffer might not be used for the first Received message so check if it exists // otherwise use the default buffer if (info == null || info.buffer == null) Array.Copy(byteData, temp, numBytesReceived); else Array.Copy(info.buffer, temp, numBytesReceived); // parse the bytes and turn it into a TFMS_Data object return new TFMS_Data(temp); } catch (SocketException) { // if something goes wrong, logoff the client return new TFMS_Data(TFMS_Command.Logout, null, getNamefromSocket(socket)); } }
/// <summary> /// this hadles the actual message forwarding ect. /// you should never call this function directly /// </summary> /// <param name="result">this encapsulates the Socket of the client</param> public void OnReceive(IAsyncResult result) { // get the socket that received data Socket clientSocket = (Socket)result.AsyncState; // get the ClientInfo from the connected client TFMS_ClientInfo CI = null; if (findIndexFromClient(clientList, clientSocket) >= 0) CI = clientList[findIndexFromClient(clientList, clientSocket)]; Console.WriteLine("\n****************************************"); Console.WriteLine("Data Received from {0}", getNamefromSocket(clientSocket)); // attempt to get the data from the client and convert it into TFMS_Data object TFMS_Data msgReceived = extractData(clientSocket, CI, result); TFMS_Data msgToSend = new TFMS_Data(); msgToSend.cmdCommand = msgReceived.cmdCommand; msgToSend.strName = msgReceived.strName; #region Interpret incoming message command // set the message to send, client info buffer size, and client info based on the incoming command switch (msgReceived.cmdCommand) { case TFMS_Command.Login: // new client logging in #region Login command Console.WriteLine("Received login from {0}", getNamefromSocket(clientSocket)); // tell the server a logon was requested logonRequested(msgReceived); // add the new client to the current list of clients TFMS_ClientInfo clientInfo = new TFMS_ClientInfo(clientSocket, msgReceived.strName); clientList.Add(clientInfo); // pass the incoming client's name to other clients msgToSend.strMessage = msgReceived.strName; clientInfo.buffer = new byte[TFMS_Constants.BUFFER_SIZE]; // dimension the clients buffer. CI = clientInfo; // CI would not have been found before since its not in the clientList so just add it now #endregion break; case TFMS_Command.Logout: // client logging out #region Logout command Console.WriteLine("Received Logout from {0}", getNamefromSocket(clientSocket)); // tell the server a logout was requested logoffRequested(msgReceived); // remove the client from the list of connected clients. clientList.RemoveAt(findIndexFromClient(clientList, clientSocket)); clientSocket.Close(); // pass the client's name to other clients msgToSend.strMessage = msgReceived.strName; #endregion break; case TFMS_Command.List: // client requesting a list of all clients #region List command Console.WriteLine("Received List request from {0}", getNamefromSocket(clientSocket)); // tell the server a list of clients was requested listRequested(msgReceived); // get the list of all currently connected clients msgToSend = GetClientListMessage(); // send the message to a single client sendTFMSmsg(msgToSend, clientSocket, new AsyncCallback(OnSend)); #endregion break; case TFMS_Command.Message: // incoming message to be broadcast #region Message command Console.WriteLine("Received TFM from {0} (size={1})", getNamefromSocket(clientSocket), CI.buffer.Length); // tell the server a message broadcast was requested relayRequested(msgReceived); // copy the message to the server's outgoing message field msgToSend.strMessage = msgReceived.strMessage; #endregion break; case TFMS_Command.MsgLen: // incoming message is greater than the current buffer size #region Long Message command Console.WriteLine("Received long TFM from {0} (size={1})", getNamefromSocket(clientSocket), CI.buffer.Length); // resize the buffer for the incoming large message CI.buffer = new byte[int.Parse(msgReceived.strMessage) + TFMS_Constants.BUFFER_SIZE]; #endregion break; default: // unrecognizable command #region Unknown command // we gracefully fail and gtfoh Console.WriteLine("Cant interpret command! Aborting this relay."); Console.WriteLine("BeginReceive from {0}", getNamefromSocket(clientSocket)); // restart the receive command clientSocket.BeginReceive(CI.buffer, 0, CI.buffer.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket); return; #endregion } #endregion // send the message to every client logged in to the server broadcastToClients(msgToSend, clientList); // after a message is broadcast, begin listening for more incoming messages // NOTE: if many users are logged in at once, the broadcast method could block other incoming messages // for future iterations of TFMS, we want the receiving command to run on a separate thread from the sending command if (msgReceived.cmdCommand != TFMS_Command.Logout) { Console.WriteLine("Waiting for data from {0}", getNamefromSocket(clientSocket)); clientSocket.BeginReceive(CI.buffer, 0, CI.buffer.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket); } }