Пример #1
0
        /// <summary>
        /// Finish establishing a connection to the server, invoke the callback in the preserved state object, and begin receiving data
        /// </summary>
        public static void Connected_to_Server(IAsyncResult state_in_an_ar_object)
        {
            // Get the state from the parameter
            Preserved_State_Object state = (Preserved_State_Object)state_in_an_ar_object.AsyncState;

            try
            {
                state.socket.EndConnect(state_in_an_ar_object);

                // Invoke the callback
                state.callback.DynamicInvoke(state);

                // Begin receiving data from the server
                state.socket.BeginReceive(state.buffer, 0, Preserved_State_Object.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
            }
            catch (SocketException)
            {
                // If there is a problem with the socket, gracefully close it down
                if (state.socket.Connected)
                {
                    state.socket.Shutdown(SocketShutdown.Both);
                    state.socket.Close();
                }

                // Invoke the callback
                state.callback.DynamicInvoke(state);
            }
        }
Пример #2
0
        /// <summary>
        /// Handles reception and storage of data
        /// </summary>
        public static void ReceiveCallback(IAsyncResult state_in_an_ar_object)
        {
            // Get the state from the parameter, declare a variable for holding count of received bytes
            Preserved_State_Object state = (Preserved_State_Object)state_in_an_ar_object.AsyncState;

            try
            {
                int bytesRead = state.socket.EndReceive(state_in_an_ar_object);

                // If bytes were read, save the decoded string and invoke the callback
                if (bytesRead > 0)
                {
                    state.data.Append(Encoding.UTF8.GetString(state.buffer, 0, bytesRead));
                    state.callback.DynamicInvoke(state);
                }
                // Otherwise we are disconnected - close the socket
                else
                {
                    //TODO: do these have to stay commented out for it to work, or does it work now?
                    //Needs to be tested again.

                    state.socket.Shutdown(SocketShutdown.Both);
                    state.socket.Close();
                }
            }
            catch (Exception)
            {
                // If there is a problem with the socket, gracefully close it down
                if (state.socket.Connected)
                {
                    state.socket.Shutdown(SocketShutdown.Both);
                    state.socket.Close();
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Method to send and receive data from client
        /// </summary>
        private void ManageData(Preserved_State_Object state)
        {
            // Try to perform the complete move or split actions
            string[] actions = Regex.Split(state.data.ToString(), @"\n");

            for (int i = 0; i < actions.Length - 1; i++)
            {
                TryMoveOrSplit(actions[i], state);
            }

            // Try to perform the last move or split action if it is complete, otherwise append what is there for later
            string lastAction = actions.Last();

            if (lastAction.Length > 1 && lastAction.Last() == ')')
            {
                TryMoveOrSplit(lastAction, state);
            }
            else
            {
                state.data = new StringBuilder(lastAction);
            }

            // Call for more client actions
            Network.I_Want_More_Data(state);
        }
Пример #4
0
        /// <summary>
        /// Main callback method for setting up a client.
        /// </summary>
        private void SetUpClient(Preserved_State_Object state)
        {
            Console.WriteLine("User " + state.data + " has connected to the server.");

            // Generate 2 random starting coords within our world, check if other players are there, then send if player won't get eaten immediately (helper method)
            double x, y;
            Cube   cube;
            string worldData;

            lock (World)
            {
                World.FindStartingCoords(out x, out y, false);
                cube = new Cube(x, y, World.GetUid(), false, state.data.ToString(), World.PLAYER_START_MASS, World.GetColor(), 0);
                World.Cubes[cube.uid] = cube;
                worldData             = World.SerializeAllCubes();

                World.DatabaseStats.Add(cube.uid, new World.StatTracker(state.data.ToString()));
            }

            state.CubeID = cube.uid;
            state.data.Clear();
            state.callback = new Network.Callback(ManageData);

            // Send the client's cube and then all of the world data
            Network.Send(state.socket, JsonConvert.SerializeObject(cube) + "\n");
            Network.Send(state.socket, worldData);

            lock (Sockets)
            {
                Sockets.Add(state.socket, new ScoreInformation(cube.uid));
            }

            // Ask for more data from client
            Network.I_Want_More_Data(state);
        }
Пример #5
0
        /// <summary>
        /// Callback method - gets the player cube from the server
        /// </summary>
        private void GetPlayerCube(Preserved_State_Object state)
        {
            // Get the player cube (and add its uid to the set of split player cubes)
            Cube c = JsonConvert.DeserializeObject <Cube>(state.data.ToString());

            PlayerSplitID.Add(PlayerID = c.uid);

            // Set the max mass to the initial player mass
            MaxMass = c.Mass;

            // Add the player cube to the world
            lock (World)
            {
                World.Cubes.Add(c.uid, c);
            }

            // Begin painting the world
            this.Paint += new System.Windows.Forms.PaintEventHandler(this.Display_Paint);
            this.Invalidate();

            // Set the default move coordinates to the player block's starting location
            PrevMouseLoc_x = (int)c.loc_x;
            PrevMouseLoc_y = (int)c.loc_y;

            // Provide the next callback and start getting game data from the server
            state.callback = new Network.Callback(SendReceiveData);
            Network.I_Want_More_Data(state);
        }
Пример #6
0
        /// <summary>
        /// Accepts a new client and begins data transferring
        /// </summary>
        public static void Accept_a_New_Client(IAsyncResult ar)
        {
            Preserved_State_Object state = (Preserved_State_Object)ar.AsyncState;

            state.socket = state.server.EndAcceptSocket(ar);

            state.socket.BeginReceive(state.buffer, 0, Preserved_State_Object.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); //Get the name, then give them their cube.
            state.server.BeginAcceptSocket(new AsyncCallback(Accept_a_New_Client), new Preserved_State_Object(state.server, state.callback));
        }
Пример #7
0
        /// <summary>
        /// Heart of the server code. Creates an async loop for accepting new clients.
        /// </summary>
        public static void Server_Awaiting_Client_Loop(Delegate callback, int port)
        {
            TcpListener server = TcpListener.Create(port);

            server.Start();
            Preserved_State_Object state = new Preserved_State_Object(server, callback);

            server.BeginAcceptSocket(new AsyncCallback(Accept_a_New_Client), state);
        }
Пример #8
0
        /// <summary>
        /// Callback for web server - builds webpages based off of queries received from the browser
        /// </summary>
        private void CreateWebPage(Preserved_State_Object state)
        {
            string query  = Regex.Split(state.data.ToString(), "\r\n")[0];
            string score  = @"GET /scores";
            string games  = @"GET /games\?player=";
            string eaten  = @"GET /eaten\?id=";
            string ending = @" HTTP/1.1";

            if (Regex.IsMatch(query, score))
            {
                /* Upon receiving "GET /scores HTTP/1.1" the server will send back an HTML web page containing a table of information reporting all recorded scores.
                 * This should include, the length of time alive, the maximum mass, the highest rank, and the number of cubes eaten.
                 * The HTML table should have one row for each player/game in the database and one column for each of the above required pieces of information.
                 * A superior solution would create links in this table to the information described below (e.g., clicking on a players name would invoke case 2 below).*/

                string dbQuery = "Select * from Players";

                Network.Send(state.socket, StatsHTML(new MySqlCommand(dbQuery), 1, "AgCubio Stats | High Scores"), true);
            }
            else if (Regex.IsMatch(query, games))
            {
                /*Upon receiving "GET /games?player=Joe HTTP/1.1" the server will send back an HTML web page containing a table of information reporting all games by the player "Joe".
                 * There should be one row for each game played by the player named in the line of text (e.g., "Joe" in the example above) and a column for each piece of information.
                 * In addition to the above information, the time of death should be shown and the number of players eaten should be shown.
                 * A superior solution would also have links to the main score table page and to the list of eaten players for a particular game.*/

                query = Regex.Replace(query, "(" + games + ")|(" + ending + ")", ""); // Get the player name

                string dbQuery = "Select * from Players where name = '" + query + "'";

                Network.Send(state.socket, StatsHTML(new MySqlCommand(dbQuery), 2, "AgCubio Stats | Player: " + query), true);
            }
            else if (Regex.IsMatch(query, eaten))
            {
                /*Upon receiving "GET /eaten?id=35 HTTP/1.1" the server should send back an HTML page containing information about the specified game session (e.g., 35 in this example).
                 * The page should contain all information about the players game, but most importantly highlight the names of players who were eaten. A superior solution would turn "eaten player" names into links to their high scores.
                 * If there the specified game does not exist, treat this as an "anything else" case as discussed below. As always, a superior solution will have links from this page to other related pages.*/

                query = Regex.Replace(query, "(" + eaten + ")|(" + ending + ")", ""); // Get the game id

                string dbQuery = "Select * from Eaten natural join Players where GameId = " + query;

                Network.Send(state.socket, StatsHTML(new MySqlCommand(dbQuery), 3, "AgCubio Stats | Game ID: " + query), true);
            }
            else
            {
                // Show an error page if the first line of text the browser sends the server is invalid
                Network.Send(state.socket, HTMLGenerator.GenerateError("Invalid web address"), true);
            }
        }
Пример #9
0
 /// <summary>
 /// Tells server we are ready to receive more data
 /// </summary>
 public static void I_Want_More_Data(Preserved_State_Object state)
 {
     try
     {
         state.socket.BeginReceive(state.buffer, 0, Preserved_State_Object.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
     }
     catch (Exception)
     {
         // If there is a problem with the socket, gracefully close it down
         if (state.socket.Connected)
         {
             state.socket.Shutdown(SocketShutdown.Both);
             state.socket.Close();
         }
     }
 }
Пример #10
0
        /// <summary>
        /// Begins establishing a connection to the server
        /// </summary>
        public static Socket Connect_to_Server(Callback callback, string hostname)
        {
            // Store the server IP address and remote endpoint
            //   MSDN: localhost can be found with the "" string.
            IPAddress  ipAddress = (hostname.ToUpper() == "LOCALHOST") ? IPAddress.Parse("::1") : IPAddress.Parse(hostname);
            IPEndPoint remoteEP  = new IPEndPoint(ipAddress, Port);

            // Make a new socket and preserved state object and begin connecting
            Socket socket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            Preserved_State_Object state = new Preserved_State_Object(socket, callback);

            // Begin establishing a connection
            socket.BeginConnect(remoteEP, new AsyncCallback(Connected_to_Server), state);

            // Return the socket
            return(state.socket);
        }
Пример #11
0
        /// <summary>
        /// Parses client requests into moves or splits
        /// </summary>
        private void TryMoveOrSplit(String str, Preserved_State_Object state)
        {
            // Get the coordinates for the move or split
            MatchCollection values = Regex.Matches(str, @"-*\d+");
            double          x      = double.Parse(values[0].Value);
            double          y      = double.Parse(values[1].Value);

            // Handle moving or splitting
            //   *NOTE: Cubes are not actually moved here, as that could lead to more or less movement per player in a given amount of time (based on connection speed)
            //          - instead, movement direction is appended to a stringbuilder and dealt with all at the same time in the server's heartbeat tick
            if (str[1] == 'm')
            {
                lock (DataReceived) { DataReceived[state.CubeID] = new Tuple <double, double>(x, y); }
            }
            else if (str[1] == 's')
            {
                lock (World) { World.Split(state.CubeID, x, y); }
            }
        }
Пример #12
0
        /// <summary>
        /// Callback method - sends the player name to the server
        /// </summary>
        private void SendName(Preserved_State_Object state)
        {
            // Pop a dialog box if the connection is not established
            if (!socket.Connected)
            {
                this.Invoke(new Action(UnableToConnect));
                return;
            }

            // Save the network thread to a private member in the GUI (for deactivation later)
            NetworkThread = Thread.CurrentThread;

            // Prevent network from getting upset over empty string names
            string name = (textBoxName.Text == "") ? " " : textBoxName.Text;

            // Provide the next callback and send the player name to the server
            state.callback = new Network.Callback(GetPlayerCube);
            Network.Send(state.socket, name);
        }
Пример #13
0
        /// <summary>
        /// Callback method - sends moves, receives data from the server
        /// </summary>
        private void SendReceiveData(Preserved_State_Object state)
        {
            if (socket.Connected)
            {
                lock (CubeData)
                {
                    // Use the StringBuilder to append the string received from the server
                    CubeData.Append(state.data);
                }

                state.data.Clear();

                // Send a move request, following the convention: '(move, dest_x, dest_y)\n'
                string move = "(move, " + PrevMouseLoc_x + ", " + PrevMouseLoc_y + ")\n";
                Network.Send(socket, move);

                // Ask for more data
                Network.I_Want_More_Data(state);
            }
        }