Skip to content

004: Client Connections

Shane DeSeranno edited this page Feb 15, 2017 · 3 revisions

Now we need to create a new class to track the state of the connection to a client. Let's create a new class called 'Client' at the root for the project. And for now, we need the Client class to have an IsConnected property, a constructor that receives necessary values like the Socket. And we will need the Poll() and Disconnect() methods.

    public class Client
    {
        private Socket m_Socket;
        private ILogger m_Logger;

        // We are considered connected if we have a valid socket object
        public bool IsConnected { get { return m_Socket != null; } }

        public Client(Socket socket, ILogger logger)
        {
            m_Socket = socket;
            m_Logger = logger;
        }

        public void Poll()
        {
            // TODO: Implement reading/processing of data
        }

        public void Disconnect()
        {
            m_Logger.LogDebug($"Disconnected");
            if (m_Socket != null)
            {
                try
                {
                    m_Socket.Shutdown(SocketShutdown.Both);
                }
                catch (Exception) { }

                m_Socket = null;
            }
        }
    }

And now, the Server needs to have a list of all connected clients that it can manage.

    public class Server
    {
        ...
        private List<Client> m_Clients = new List<Client>();
        ...
    }

Find the TODO comments for working with the clients and implement them:

        public void Poll()
        {
            // Check for new connections
            while (m_Listener.Pending())
            {
                Task<Socket> acceptTask = m_Listener.AcceptSocketAsync();
                acceptTask.Wait();

                Socket socket = acceptTask.Result;
                m_Logger.LogDebug($"New Client: {socket.RemoteEndPoint.ToString()}");

                // Create and add client list
                m_Clients.Add(new Client(socket, m_LoggerFactory.CreateLogger(socket.RemoteEndPoint.ToString())));
            }

            // Poll each client for activity
            m_Clients.ForEach(c => c.Poll());

            // Remove all disconnected clients
            m_Clients.RemoveAll(c => c.IsConnected == false);
        }

        public void Stop()
        {
            if (m_Listener != null)
            {
                m_Logger.LogInformation("Shutting down...");

                // Disconnect clients and clear clients
                m_Clients.ForEach(c => c.Disconnect());
                m_Clients.Clear();

                m_Listener.Stop();
                m_Listener = null;

                m_Logger.LogInformation("Stopped!");
            }
        }

As you can see, we just create a new Client object for each connection and add it to a list. This list is then polled every time we poll the server. And if, during that poll, a client gets disconnected, then we'll remove it from the list. Finally, when the server is stopped, it disconnects all active clients and clears the list.

You can run and test this again, but it behaves the same as before. However, we are now ready to start reading data from the socket, but first, we'll take a break and start discussing the RFCs.

The latest code, at this point can be see at tag Client Connections

When you are ready, go to the next section: RFC 4253