public static void TestShape(Shape reference, CreateShapeFunction createShape, ShapeValidationFunction validate)
        {
            ServerInfoMessage info = ServerInfoMessage.Default;

            info.CoordinateFrame = CoordinateFrame.XYZ;

            ServerSettings serverSettings = ServerSettings.Default;

            serverSettings.Flags    &= ~(ServerFlag.Collate | ServerFlag.Compress);
            serverSettings.PortRange = 1000;
            IServer server = new TcpServer(serverSettings);

            // std::cout << "Start on port " << serverSettings.listenPort << std::endl;
            Assert.True(server.ConnectionMonitor.Start(ConnectionMonitorMode.Asynchronous));
            // std::cout << "Server listening on port " << server.connectionMonitor()->port() << std::endl;;

            // Create client and connect.

            TcpClient client = new TcpClient("127.0.0.1", server.ConnectionMonitor.Port);

            // Wait for connection.
            if (server.ConnectionMonitor.WaitForConnections(5000u) > 0)
            {
                server.ConnectionMonitor.CommitConnections(null);
            }

            Assert.True(server.ConnectionCount > 0);
            Assert.True(client.Connected);

            // Send server messages from another thread. Otherwise large packets may block.
            Thread sendThread = new Thread(() =>
            {
                Assert.True(server.Create(reference) > 0);
                Assert.True(server.UpdateTransfers(0) >= 0);
                Assert.True(server.UpdateFrame(0.0f) > 0);

                // Send end message.
                ControlMessage ctrlMsg = new ControlMessage();
                Assert.True(ServerUtil.SendMessage(server, (ushort)RoutingID.Control, (ushort)ControlMessageID.End, ctrlMsg) > 0);
                Assert.True(server.UpdateFrame(0.0f) > 0);
            });

            sendThread.Start();

            // Process client messages.
            ValidateClient(client, reference, info, createShape, validate);

            client.Close();

            sendThread.Join();
            server.Close();

            server.ConnectionMonitor.Stop();
            server.ConnectionMonitor.Join();
        }
        static void Main(string[] args)
        {
            if (HaveOption("help", args))
            {
                ShowUsage();
                return;
            }

            Console.CancelKeyPress += new ConsoleCancelEventHandler(ControlCHandler);

            ServerSettings serverSettings = ServerSettings.Default;

            serverSettings.PortRange = 10;
            ServerInfoMessage info = ServerInfoMessage.Default;

            info.CoordinateFrame = CoordinateFrame.XYZ;
            if (HaveOption("compress", args))
            {
                serverSettings.Flags |= ServerFlag.Compress;
            }

            IServer             server    = new TcpServer(serverSettings, info);
            List <Shapes.Shape> shapes    = new List <Shapes.Shape>();
            List <ShapeMover>   movers    = new List <ShapeMover>();
            List <Resource>     resources = new List <Resource>();
            Ids ids = new Ids();

            ids.NextShapeId = 1;

            CreateAxes(ids, shapes, movers, resources, args);
            CreateShapes(ids, shapes, movers, resources, args);

            const int targetFrameTimeMs = 1000 / 30;
            int       updateElapsedMs   = 0;
            float     dt   = 0;
            float     time = 0;

            Stopwatch frameTimer = new Stopwatch();
            Stopwatch sleepTimer = new Stopwatch();

            // Register shapes with server.
            foreach (Shapes.Shape shape in shapes)
            {
                server.Create(shape);
            }

            if (!server.ConnectionMonitor.Start(ConnectionMonitorMode.Asynchronous))
            {
                Console.WriteLine("Failed to start listen socket.");
                return;
            }
            Console.WriteLine(string.Format("Listening on port {0}", server.ConnectionMonitor.Port));

            frameTimer.Start();
            while (!Quit)
            {
                frameTimer.Stop();
                dt    = frameTimer.ElapsedMilliseconds * 1e-3f;
                time += dt;
                frameTimer.Reset();
                frameTimer.Start();
                sleepTimer.Reset();
                sleepTimer.Start();

                foreach (ShapeMover mover in movers)
                {
                    mover.Update(time, dt);
                    server.Update(mover.Shape);
                }

                server.UpdateFrame(dt);

                if (server.ConnectionMonitor.Mode == ConnectionMonitorMode.Synchronous)
                {
                    server.ConnectionMonitor.MonitorConnections();
                }
                server.ConnectionMonitor.CommitConnections((IServer s, IConnection connection) =>
                {
                    foreach (Shapes.Shape shape in shapes)
                    {
                        connection.Create(shape);
                    }
                });

                server.UpdateTransfers(64 * 1024);

                Console.Write(string.Format("\rFrame {0}: {1} connection(s)      ", dt, server.ConnectionCount));
                // Console Flush?

                // Work out how long to sleep for.
                sleepTimer.Stop();
                updateElapsedMs = (int)sleepTimer.ElapsedMilliseconds;
                if (updateElapsedMs + 1 < targetFrameTimeMs)
                {
                    // Sleep until the next frame. Sleep for a millisecond less than we need to allow
                    // a bit of overhead.
                    System.Threading.Thread.Sleep(targetFrameTimeMs - (updateElapsedMs + 1));
                }
            }

            foreach (Shapes.Shape shape in shapes)
            {
                server.Destroy(shape);
            }

            server.UpdateFrame(0);

            server.ConnectionMonitor.Stop();
            server.ConnectionMonitor.Join();
        }