public static async Task Main(string[] args)
        {
            // Manual wire up of the server
            var services = new ServiceCollection();

            services.AddLogging(builder =>
            {
                builder.SetMinimumLevel(LogLevel.Debug);
                builder.AddConsole();
            });

            services.AddScoped <MessageHandler <HelloServerMessage>, HelloServerMessageHandler>();
            services.Add <MessageMetadataParser, MessageMetadata>();
            services.AddSingleton(sp =>
            {
                var builder = new ServerFramingBuilder(sp);
                builder.Mappings.Add((HelloServerMessage.Id, typeof(HelloServerMessage)));
                builder.MessageWriter = new MessageWriter(builder.Parser);
                builder.MessageReader = new MessageReader();
                builder.UseMessageEncoder();

                return(builder.Build());
            });

            var serviceProvider = services.BuildServiceProvider();

            var server = new ServerBuilder(serviceProvider)
                         .UseSockets(sockets => sockets.Listen(IPAddress.Loopback, 5000,
                                                               builder => builder.UseConnectionHandler <ServerConnectionHandler>()))
                         .Build();

            var logger = serviceProvider.GetRequiredService <ILoggerFactory>().CreateLogger <Program>();
            await server.StartAsync();

            foreach (var ep in server.EndPoints)
            {
                logger.LogInformation("Listening on {EndPoint}", ep);
            }

            var tcs = new TaskCompletionSource <object>();

            Console.CancelKeyPress += (sender, e) => tcs.TrySetResult(null);

            await tcs.Task;
            await server.StopAsync();
        }
        static async Task Main(string[] args)
        {
            // Manual wire up of the client
            var services = new ServiceCollection().AddLogging(builder =>
            {
                builder.SetMinimumLevel(LogLevel.Debug);
                builder.AddConsole();
            });

            services.AddScoped <MessageHandler <HandshakeMessage>, HandshakeMessageHandler>();
            services.Add <MessageMetadataParser, MessageMetadata>();
            services.AddSingleton <ClientConnectionHandler>();
            services.AddSingleton(sp =>
            {
                var builder = new ServerFramingBuilder(sp);
                builder.Mappings.Add((HandshakeMessage.Id, typeof(HandshakeMessage)));
                builder.MessageWriter = new MessageWriter(builder.Parser);
                builder.MessageReader = new MessageReader();
                builder.UseMessageEncoder();

                return(builder.Build());
            });

            var serviceProvider   = services.BuildServiceProvider();
            var connectionHandler = serviceProvider
                                    .GetRequiredService <ClientConnectionHandler>();
            var clientFactory = new SocketConnectionFactory();

            Console.WriteLine("Press any key to start connection.");
            Console.ReadKey();

            await using var connection = await clientFactory.ConnectAsync(
                            new IPEndPoint (IPAddress.Loopback, 5000));

            await connectionHandler.OnConnectedAsync(connection).ConfigureAwait(false);
        }