{"id":13594806,"url":"https://github.com/chronoxor/NetCoreServer","last_synced_at":"2025-04-09T10:32:05.420Z","repository":{"id":37753897,"uuid":"166123164","full_name":"chronoxor/NetCoreServer","owner":"chronoxor","description":"Ultra fast and low latency asynchronous socket server \u0026 client C# .NET Core library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K connections problem solution","archived":false,"fork":false,"pushed_at":"2024-04-27T09:51:41.000Z","size":20616,"stargazers_count":2924,"open_issues_count":182,"forks_count":596,"subscribers_count":95,"default_branch":"master","last_synced_at":"2025-04-05T09:01:45.610Z","etag":null,"topics":["async","http","http-server","https","https-server","low-latency","performance","socket-client","socket-server","ssl","tcp-client","tcp-server","tls","udp-client","udp-server","websocket","websocket-server"],"latest_commit_sha":null,"homepage":"https://chronoxor.github.io/NetCoreServer","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chronoxor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-16T22:41:53.000Z","updated_at":"2025-04-04T08:28:44.000Z","dependencies_parsed_at":"2023-11-19T20:21:59.523Z","dependency_job_id":"39b64678-e4e0-454d-a4a9-fada3354029b","html_url":"https://github.com/chronoxor/NetCoreServer","commit_stats":{"total_commits":378,"total_committers":9,"mean_commits":42.0,"dds":0.03968253968253965,"last_synced_commit":"eef988d7a0ba767b06cc3277fc858850cd3149c4"},"previous_names":[],"tags_count":60,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chronoxor%2FNetCoreServer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chronoxor%2FNetCoreServer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chronoxor%2FNetCoreServer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chronoxor%2FNetCoreServer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chronoxor","download_url":"https://codeload.github.com/chronoxor/NetCoreServer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247947842,"owners_count":21023065,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","http","http-server","https","https-server","low-latency","performance","socket-client","socket-server","ssl","tcp-client","tcp-server","tls","udp-client","udp-server","websocket","websocket-server"],"created_at":"2024-08-01T16:01:39.409Z","updated_at":"2025-04-09T10:32:00.409Z","avatar_url":"https://github.com/chronoxor.png","language":"C#","readme":"# NetCoreServer\n\n[![Awesome .NET](https://awesome.re/badge.svg)](https://github.com/quozd/awesome-dotnet)\n[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)\n[![Release](https://img.shields.io/github/release/chronoxor/NetCoreServer.svg?sort=semver)](https://github.com/chronoxor/NetCoreServer/releases)\n[![NuGet](https://img.shields.io/nuget/v/NetCoreServer)](https://www.nuget.org/packages/NetCoreServer)\n\u003cbr/\u003e\n[![Linux](https://github.com/chronoxor/NetCoreServer/actions/workflows/build-linux.yml/badge.svg)](https://github.com/chronoxor/NetCoreServer/actions/workflows/build-linux.yml)\n[![MacOS](https://github.com/chronoxor/NetCoreServer/actions/workflows/build-macos.yml/badge.svg)](https://github.com/chronoxor/NetCoreServer/actions/workflows/build-macos.yml)\n[![Windows (Visual Studio)](https://github.com/chronoxor/NetCoreServer/actions/workflows/build-windows.yml/badge.svg)](https://github.com/chronoxor/NetCoreServer/actions/workflows/build-windows.yml)\n\nUltra fast and low latency asynchronous socket server \u0026 client C# .NET Core\nlibrary with support TCP, SSL, UDP, Unix Domain Socket, HTTP, HTTPS, WebSocket protocols and [10K connections problem](https://en.wikipedia.org/wiki/C10k_problem)\nsolution.\n\nHas integration with high-level message protocol based on [Fast Binary Encoding](https://github.com/chronoxor/FastBinaryEncoding)\n\n[NetCoreServer documentation](https://chronoxor.github.io/NetCoreServer)\u003cbr/\u003e\n[NetCoreServer downloads](https://github.com/chronoxor/NetCoreServer/releases)\u003cbr/\u003e\n\n# Contents\n  * [Features](#features)\n  * [Requirements](#requirements)\n  * [How to build?](#how-to-build)\n  * [Examples](#examples)\n    * [Example: TCP chat server](#example-tcp-chat-server)\n    * [Example: TCP chat client](#example-tcp-chat-client)\n    * [Example: SSL chat server](#example-ssl-chat-server)\n    * [Example: SSL chat client](#example-ssl-chat-client)\n    * [Example: UDP echo server](#example-udp-echo-server)\n    * [Example: UDP echo client](#example-udp-echo-client)\n    * [Example: UDP multicast server](#example-udp-multicast-server)\n    * [Example: UDP multicast client](#example-udp-multicast-client)\n    * [Example: Unix Domain Socket chat server](#example-unix-domain-socket-chat-server)\n    * [Example: Unix Domain Socket chat client](#example-unix-domain-socket-chat-client)\n    * [Example: Simple protocol](#example-simple-protocol)\n    * [Example: Simple protocol server](#example-simple-protocol-server)\n    * [Example: Simple protocol client](#example-simple-protocol-client)\n    * [Example: HTTP server](#example-http-server)\n    * [Example: HTTP client](#example-http-client)\n    * [Example: HTTPS server](#example-https-server)\n    * [Example: HTTPS client](#example-https-client)\n    * [Example: WebSocket chat server](#example-websocket-chat-server)\n    * [Example: WebSocket chat client](#example-websocket-chat-client)\n    * [Example: WebSocket secure chat server](#example-websocket-secure-chat-server)\n    * [Example: WebSocket secure chat client](#example-websocket-secure-chat-client)\n  * [Performance](#performance)\n    * [Benchmark: Round-Trip](#benchmark-round-trip)\n      * [TCP echo server](#tcp-echo-server)\n      * [SSL echo server](#ssl-echo-server)\n      * [UDP echo server](#udp-echo-server)\n      * [Unix Domain Socket echo server](#unix-domain-socket-echo-server)\n      * [Simple protocol server](#simple-protocol-server)\n      * [WebSocket echo server](#websocket-echo-server)\n      * [WebSocket secure echo server](#websocket-secure-echo-server)\n    * [Benchmark: Multicast](#benchmark-multicast)\n      * [TCP multicast server](#tcp-multicast-server)\n      * [SSL multicast server](#ssl-multicast-server)\n      * [UDP multicast server](#udp-multicast-server)\n      * [Unix Domain Socket multicast server](#unix-domain-socket-multicast-server)\n      * [WebSocket multicast server](#websocket-multicast-server)\n      * [WebSocket secure multicast server](#websocket-secure-multicast-server)\n    * [Benchmark: Web Server](#benchmark-web-server)\n      * [HTTP Trace server](#http-trace-server)\n      * [HTTPS Trace server](#https-trace-server)\n  * [OpenSSL certificates](#openssl-certificates)\n    * [Production](#production)\n    * [Development](#development)\n    * [Certificate Authority](#certificate-authority)\n    * [SSL Server certificate](#ssl-server-certificate)\n    * [SSL Client certificate](#ssl-client-certificate)\n    * [Diffie-Hellman key exchange](#diffie-hellman-key-exchange)\n\n# Features\n* Cross platform (Linux, MacOS, Windows)\n* Asynchronous communication\n* Supported transport protocols: [TCP](#example-tcp-chat-server), [SSL](#example-ssl-chat-server),\n  [UDP](#example-udp-echo-server), [UDP multicast](#example-udp-multicast-server),\n  [Unix Domain Socket](#example-unix-domain-socket-chat-server)\n* Supported Web protocols: [HTTP](#example-http-server), [HTTPS](#example-https-server),\n  [WebSocket](#example-websocket-chat-server), [WebSocket secure](#example-websocket-secure-chat-server)\n* Supported [Swagger OpenAPI](https://swagger.io/specification/) iterative documentation\n* Supported message protocol based on [Fast Binary Encoding](https://github.com/chronoxor/FastBinaryEncoding)\n\n# Requirements\n* Linux\n* MacOS\n* Windows\n* [.NET 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)\n* [7-Zip](https://www.7-zip.org)\n* [cmake](https://www.cmake.org)\n* [git](https://git-scm.com)\n* [Visual Studio](https://www.visualstudio.com)\n\nOptional:\n* [Rider](https://www.jetbrains.com/rider)\n\n# How to build?\n\n### Setup repository\n```shell\ngit clone https://github.com/chronoxor/NetCoreServer.git\ncd NetCoreServer\n```\n\n### Linux\n```shell\ncd build\n./unix.sh\n```\n\n### MacOS\n```shell\ncd build\n./unix.sh\n```\n\n### Windows (Visual Studio)\nOpen and build [NetCoreServer.sln](https://github.com/chronoxor/NetCoreServer/blob/master/NetCoreServer.sln) or run the build script:\n```shell\ncd build\nvs.bat\n```\n\nThe build script will create \"release\" directory with zip files:\n* NetCoreServer.zip - C# Server assembly\n* Benchmarks.zip - C# Server benchmarks\n* Examples.zip - C# Server examples\n\n# Examples\n\n## Example: TCP chat server\nHere comes the example of the TCP chat server. It handles multiple TCP client\nsessions and multicast received message from any session to all ones. Also it\nis possible to send admin message directly from the server.\n\n```c#\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\nusing NetCoreServer;\n\nnamespace TcpChatServer\n{\n    class ChatSession : TcpSession\n    {\n        public ChatSession(TcpServer server) : base(server) {}\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"Chat TCP session with Id {Id} connected!\");\n\n            // Send invite message\n            string message = \"Hello from TCP chat! Please send a message or '!' to disconnect the client!\";\n            SendAsync(message);\n        }\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"Chat TCP session with Id {Id} disconnected!\");\n        }\n\n        protected override void OnReceived(byte[] buffer, long offset, long size)\n        {\n            string message = Encoding.UTF8.GetString(buffer, (int)offset, (int)size);\n            Console.WriteLine(\"Incoming: \" + message);\n\n            // Multicast message to all connected sessions\n            Server.Multicast(message);\n\n            // If the buffer starts with '!' the disconnect the current session\n            if (message == \"!\")\n                Disconnect();\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat TCP session caught an error with code {error}\");\n        }\n    }\n\n    class ChatServer : TcpServer\n    {\n        public ChatServer(IPAddress address, int port) : base(address, port) {}\n\n        protected override TcpSession CreateSession() { return new ChatSession(this); }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat TCP server caught an error with code {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // TCP server port\n            int port = 1111;\n            if (args.Length \u003e 0)\n                port = int.Parse(args[0]);\n\n            Console.WriteLine($\"TCP server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create a new TCP chat server\n            var server = new ChatServer(IPAddress.Any, port);\n\n            // Start the server\n            Console.Write(\"Server starting...\");\n            server.Start();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Multicast admin message to all sessions\n                line = \"(admin) \" + line;\n                server.Multicast(line);\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: TCP chat client\nHere comes the example of the TCP chat client. It connects to the TCP chat\nserver and allows to send message to it and receive new messages.\n\n```c#\nusing System;\nusing System.Net.Sockets;\nusing System.Text;\nusing System.Threading;\nusing TcpClient = NetCoreServer.TcpClient;\n\nnamespace TcpChatClient\n{\n    class ChatClient : TcpClient\n    {\n        public ChatClient(string address, int port) : base(address, port) {}\n\n        public void DisconnectAndStop()\n        {\n            _stop = true;\n            DisconnectAsync();\n            while (IsConnected)\n                Thread.Yield();\n        }\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"Chat TCP client connected a new session with Id {Id}\");\n        }\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"Chat TCP client disconnected a session with Id {Id}\");\n\n            // Wait for a while...\n            Thread.Sleep(1000);\n\n            // Try to connect again\n            if (!_stop)\n                ConnectAsync();\n        }\n\n        protected override void OnReceived(byte[] buffer, long offset, long size)\n        {\n            Console.WriteLine(Encoding.UTF8.GetString(buffer, (int)offset, (int)size));\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat TCP client caught an error with code {error}\");\n        }\n\n        private bool _stop;\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // TCP server address\n            string address = \"127.0.0.1\";\n            if (args.Length \u003e 0)\n                address = args[0];\n\n            // TCP server port\n            int port = 1111;\n            if (args.Length \u003e 1)\n                port = int.Parse(args[1]);\n\n            Console.WriteLine($\"TCP server address: {address}\");\n            Console.WriteLine($\"TCP server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create a new TCP chat client\n            var client = new ChatClient(address, port);\n\n            // Connect the client\n            Console.Write(\"Client connecting...\");\n            client.ConnectAsync();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Disconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client disconnecting...\");\n                    client.DisconnectAsync();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Send the entered text to the chat server\n                client.SendAsync(line);\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.DisconnectAndStop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: SSL chat server\nHere comes the example of the SSL chat server. It handles multiple SSL client\nsessions and multicast received message from any session to all ones. Also it\nis possible to send admin message directly from the server.\n\nThis example is very similar to the TCP one except the code that prepares SSL\ncontext and handshake handler.\n\n```c#\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Text;\nusing NetCoreServer;\n\nnamespace SslChatServer\n{\n    class ChatSession : SslSession\n    {\n        public ChatSession(SslServer server) : base(server) {}\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"Chat SSL session with Id {Id} connected!\");\n        }\n\n        protected override void OnHandshaked()\n        {\n            Console.WriteLine($\"Chat SSL session with Id {Id} handshaked!\");\n\n            // Send invite message\n            string message = \"Hello from SSL chat! Please send a message or '!' to disconnect the client!\";\n            Send(message);\n        }\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"Chat SSL session with Id {Id} disconnected!\");\n        }\n\n        protected override void OnReceived(byte[] buffer, long offset, long size)\n        {\n            string message = Encoding.UTF8.GetString(buffer, (int)offset, (int)size);\n            Console.WriteLine(\"Incoming: \" + message);\n\n            // Multicast message to all connected sessions\n            Server.Multicast(message);\n\n            // If the buffer starts with '!' the disconnect the current session\n            if (message == \"!\")\n                Disconnect();\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat SSL session caught an error with code {error}\");\n        }\n    }\n\n    class ChatServer : SslServer\n    {\n        public ChatServer(SslContext context, IPAddress address, int port) : base(context, address, port) {}\n\n        protected override SslSession CreateSession() { return new ChatSession(this); }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat SSL server caught an error with code {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // SSL server port\n            int port = 2222;\n            if (args.Length \u003e 0)\n                port = int.Parse(args[0]);\n\n            Console.WriteLine($\"SSL server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create and prepare a new SSL server context\n            var context = new SslContext(SslProtocols.Tls12, new X509Certificate2(\"server.pfx\", \"qwerty\"));\n\n            // Create a new SSL chat server\n            var server = new ChatServer(context, IPAddress.Any, port);\n\n            // Start the server\n            Console.Write(\"Server starting...\");\n            server.Start();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Multicast admin message to all sessions\n                line = \"(admin) \" + line;\n                server.Multicast(line);\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: SSL chat client\nHere comes the example of the SSL chat client. It connects to the SSL chat\nserver and allows to send message to it and receive new messages.\n\nThis example is very similar to the TCP one except the code that prepares SSL\ncontext and handshake handler.\n\n```c#\nusing System;\nusing System.Net.Sockets;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Text;\nusing System.Threading;\nusing NetCoreServer;\n\nnamespace SslChatClient\n{\n    class ChatClient : SslClient\n    {\n        public ChatClient(SslContext context, string address, int port) : base(context, address, port) {}\n\n        public void DisconnectAndStop()\n        {\n            _stop = true;\n            DisconnectAsync();\n            while (IsConnected)\n                Thread.Yield();\n        }\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"Chat SSL client connected a new session with Id {Id}\");\n        }\n\n        protected override void OnHandshaked()\n        {\n            Console.WriteLine($\"Chat SSL client handshaked a new session with Id {Id}\");\n        }\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"Chat SSL client disconnected a session with Id {Id}\");\n\n            // Wait for a while...\n            Thread.Sleep(1000);\n\n            // Try to connect again\n            if (!_stop)\n                ConnectAsync();\n        }\n\n        protected override void OnReceived(byte[] buffer, long offset, long size)\n        {\n            Console.WriteLine(Encoding.UTF8.GetString(buffer, (int)offset, (int)size));\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat SSL client caught an error with code {error}\");\n        }\n\n        private bool _stop;\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // SSL server address\n            string address = \"127.0.0.1\";\n            if (args.Length \u003e 0)\n                address = args[0];\n\n            // SSL server port\n            int port = 2222;\n            if (args.Length \u003e 1)\n                port = int.Parse(args[1]);\n\n            Console.WriteLine($\"SSL server address: {address}\");\n            Console.WriteLine($\"SSL server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create and prepare a new SSL client context\n            var context = new SslContext(SslProtocols.Tls12, new X509Certificate2(\"client.pfx\", \"qwerty\"), (sender, certificate, chain, sslPolicyErrors) =\u003e true);\n\n            // Create a new SSL chat client\n            var client = new ChatClient(context, address, port);\n\n            // Connect the client\n            Console.Write(\"Client connecting...\");\n            client.ConnectAsync();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Disconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client disconnecting...\");\n                    client.DisconnectAsync();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Send the entered text to the chat server\n                client.SendAsync(line);\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.DisconnectAndStop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: UDP echo server\nHere comes the example of the UDP echo server. It receives a datagram mesage\nfrom any UDP client and resend it back without any changes.\n\n```c#\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\nusing NetCoreServer;\n\nnamespace UdpEchoServer\n{\n    class EchoServer : UdpServer\n    {\n        public EchoServer(IPAddress address, int port) : base(address, port) {}\n\n        protected override void OnStarted()\n        {\n            // Start receive datagrams\n            ReceiveAsync();\n        }\n\n        protected override void OnReceived(EndPoint endpoint, byte[] buffer, long offset, long size)\n        {\n            Console.WriteLine(\"Incoming: \" + Encoding.UTF8.GetString(buffer, (int)offset, (int)size));\n\n            // Echo the message back to the sender\n            SendAsync(endpoint, buffer, 0, size);\n        }\n\n        protected override void OnSent(EndPoint endpoint, long sent)\n        {\n            // Continue receive datagrams\n            ReceiveAsync();\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Echo UDP server caught an error with code {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // UDP server port\n            int port = 3333;\n            if (args.Length \u003e 0)\n                port = int.Parse(args[0]);\n\n            Console.WriteLine($\"UDP server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create a new UDP echo server\n            var server = new EchoServer(IPAddress.Any, port);\n\n            // Start the server\n            Console.Write(\"Server starting...\");\n            server.Start();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                }\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: UDP echo client\nHere comes the example of the UDP echo client. It sends user datagram message\nto UDP server and listen for response.\n\n```c#\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\nusing System.Threading;\nusing UdpClient = NetCoreServer.UdpClient;\n\nnamespace UdpEchoClient\n{\n    class EchoClient : UdpClient\n    {\n        public EchoClient(string address, int port) : base(address, port) {}\n\n        public void DisconnectAndStop()\n        {\n            _stop = true;\n            Disconnect();\n            while (IsConnected)\n                Thread.Yield();\n        }\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"Echo UDP client connected a new session with Id {Id}\");\n\n            // Start receive datagrams\n            ReceiveAsync();\n        }\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"Echo UDP client disconnected a session with Id {Id}\");\n\n            // Wait for a while...\n            Thread.Sleep(1000);\n\n            // Try to connect again\n            if (!_stop)\n                Connect();\n        }\n\n        protected override void OnReceived(EndPoint endpoint, byte[] buffer, long offset, long size)\n        {\n            Console.WriteLine(\"Incoming: \" + Encoding.UTF8.GetString(buffer, (int)offset, (int)size));\n\n            // Continue receive datagrams\n            ReceiveAsync();\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Echo UDP client caught an error with code {error}\");\n        }\n\n        private bool _stop;\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // UDP server address\n            string address = \"127.0.0.1\";\n            if (args.Length \u003e 0)\n                address = args[0];\n\n            // UDP server port\n            int port = 3333;\n            if (args.Length \u003e 1)\n                port = int.Parse(args[1]);\n\n            Console.WriteLine($\"UDP server address: {address}\");\n            Console.WriteLine($\"UDP server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create a new TCP chat client\n            var client = new EchoClient(address, port);\n\n            // Connect the client\n            Console.Write(\"Client connecting...\");\n            client.Connect();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Disconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client disconnecting...\");\n                    client.Disconnect();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Send the entered text to the chat server\n                client.Send(line);\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.DisconnectAndStop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: UDP multicast server\nHere comes the example of the UDP multicast server. It use multicast IP address\nto multicast datagram messages to all client that joined corresponding UDP\nmulticast group.\n\n```c#\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing NetCoreServer;\n\nnamespace UdpMulticastServer\n{\n    class MulticastServer : UdpServer\n    {\n        public MulticastServer(IPAddress address, int port) : base(address, port) {}\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Multicast UDP server caught an error with code {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // UDP multicast address\n            string multicastAddress = \"239.255.0.1\";\n            if (args.Length \u003e 0)\n                multicastAddress = args[0];\n\n            // UDP multicast port\n            int multicastPort = 3334;\n            if (args.Length \u003e 1)\n                multicastPort = int.Parse(args[1]);\n\n            Console.WriteLine($\"UDP multicast address: {multicastAddress}\");\n            Console.WriteLine($\"UDP multicast port: {multicastPort}\");\n\n            Console.WriteLine();\n\n            // Create a new UDP multicast server\n            var server = new MulticastServer(IPAddress.Any, 0);\n\n            // Start the multicast server\n            Console.Write(\"Server starting...\");\n            server.Start(multicastAddress, multicastPort);\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Multicast admin message to all sessions\n                line = \"(admin) \" + line;\n                server.Multicast(line);\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: UDP multicast client\nHere comes the example of the UDP multicast client. It use multicast IP address\nand joins UDP multicast group in order to receive multicasted datagram messages\nfrom UDP server.\n\n```c#\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\nusing System.Threading;\nusing UdpClient = NetCoreServer.UdpClient;\n\nnamespace UdpMulticastClient\n{\n    class MulticastClient : UdpClient\n    {\n        public string Multicast;\n\n        public MulticastClient(string address, int port) : base(address, port) {}\n\n        public void DisconnectAndStop()\n        {\n            _stop = true;\n            Disconnect();\n            while (IsConnected)\n                Thread.Yield();\n        }\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"Multicast UDP client connected a new session with Id {Id}\");\n\n            // Join UDP multicast group\n            JoinMulticastGroup(Multicast);\n\n            // Start receive datagrams\n            ReceiveAsync();\n        }\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"Multicast UDP client disconnected a session with Id {Id}\");\n\n            // Wait for a while...\n            Thread.Sleep(1000);\n\n            // Try to connect again\n            if (!_stop)\n                Connect();\n        }\n\n        protected override void OnReceived(EndPoint endpoint, byte[] buffer, long offset, long size)\n        {\n            Console.WriteLine(\"Incoming: \" + Encoding.UTF8.GetString(buffer, (int)offset, (int)size));\n\n            // Continue receive datagrams\n            ReceiveAsync();\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Multicast UDP client caught an error with code {error}\");\n        }\n\n        private bool _stop;\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // UDP listen address\n            string listenAddress = \"0.0.0.0\";\n            if (args.Length \u003e 0)\n                listenAddress = args[0];\n\n            // UDP multicast address\n            string multicastAddress = \"239.255.0.1\";\n            if (args.Length \u003e 1)\n                multicastAddress = args[1];\n\n            // UDP multicast port\n            int multicastPort = 3334;\n            if (args.Length \u003e 2)\n                multicastPort = int.Parse(args[2]);\n\n            Console.WriteLine($\"UDP listen address: {listenAddress}\");\n            Console.WriteLine($\"UDP multicast address: {multicastAddress}\");\n            Console.WriteLine($\"UDP multicast port: {multicastPort}\");\n\n            Console.WriteLine();\n\n            // Create a new TCP chat client\n            var client = new MulticastClient(listenAddress, multicastPort);\n            client.SetupMulticast(true);\n            client.Multicast = multicastAddress;\n\n            // Connect the client\n            Console.Write(\"Client connecting...\");\n            client.Connect();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Disconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client disconnecting...\");\n                    client.Disconnect();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.DisconnectAndStop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: Unix Domain Socket chat server\nHere comes the example of the  Unix  Domain  Socket  chat  server.  It  handles\nmultiple Unix Domain Socket client sessions and multicast received message from\nany session to all ones. Also it is possible to  send  admin  message  directly\nfrom the server.\n\n```c#\nusing System;\nusing System.IO;\nusing System.Net.Sockets;\nusing System.Text;\nusing NetCoreServer;\n\nnamespace UdsChatServer\n{\n    class ChatSession : UdsSession\n    {\n        public ChatSession(UdsServer server) : base(server) {}\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"Chat Unix Domain Socket session with Id {Id} connected!\");\n\n            // Send invite message\n            string message = \"Hello from Unix Domain Socket chat! Please send a message or '!' to disconnect the client!\";\n            SendAsync(message);\n        }\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"Chat Unix Domain Socket session with Id {Id} disconnected!\");\n        }\n\n        protected override void OnReceived(byte[] buffer, long offset, long size)\n        {\n            string message = Encoding.UTF8.GetString(buffer, (int)offset, (int)size);\n            Console.WriteLine(\"Incoming: \" + message);\n\n            // Multicast message to all connected sessions\n            Server.Multicast(message);\n\n            // If the buffer starts with '!' the disconnect the current session\n            if (message == \"!\")\n                Disconnect();\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat Unix Domain Socket session caught an error with code {error}\");\n        }\n    }\n\n    class ChatServer : UdsServer\n    {\n        public ChatServer(string path) : base(path) {}\n\n        protected override UdsSession CreateSession() { return new ChatSession(this); }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat Unix Domain Socket server caught an error with code {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // Unix Domain Socket path\n            string path = Path.Combine(Path.GetTempPath(), \"chat.sock\");\n            if (args.Length \u003e 0)\n                path = args[0];\n\n            Console.WriteLine($\"Unix Domain Socket server path: {path}\");\n\n            Console.WriteLine();\n\n            // Create a new Unix Domain Socket chat server\n            var server = new ChatServer(path);\n\n            // Start the server\n            Console.Write(\"Server starting...\");\n            server.Start();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Multicast admin message to all sessions\n                line = \"(admin) \" + line;\n                server.Multicast(line);\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: Unix Domain Socket chat client\nHere comes the example of the Unix Domain Socket chat client.  It  connects  to\nthe Unix Domain Socket chat server and allows to send message to it and receive\nnew messages.\n\n```c#\nusing System;\nusing System.IO;\nusing System.Net.Sockets;\nusing System.Text;\nusing System.Threading;\nusing UdsClient = NetCoreServer.UdsClient;\n\nnamespace UdsChatClient\n{\n    class ChatClient : UdsClient\n    {\n        public ChatClient(string path) : base(path) {}\n\n        public void DisconnectAndStop()\n        {\n            _stop = true;\n            DisconnectAsync();\n            while (IsConnected)\n                Thread.Yield();\n        }\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"Chat Unix Domain Socket client connected a new session with Id {Id}\");\n        }\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"Chat Unix Domain Socket client disconnected a session with Id {Id}\");\n\n            // Wait for a while...\n            Thread.Sleep(1000);\n\n            // Try to connect again\n            if (!_stop)\n                ConnectAsync();\n        }\n\n        protected override void OnReceived(byte[] buffer, long offset, long size)\n        {\n            Console.WriteLine(Encoding.UTF8.GetString(buffer, (int)offset, (int)size));\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat Unix Domain Socket client caught an error with code {error}\");\n        }\n\n        private bool _stop;\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // Unix Domain Socket path\n            string path = Path.Combine(Path.GetTempPath(), \"chat.sock\");\n            if (args.Length \u003e 0)\n                path = args[0];\n\n            Console.WriteLine($\"Unix Domain Socket server path: {path}\");\n\n            Console.WriteLine();\n\n            // Create a new Unix Domain Socket chat client\n            var client = new ChatClient(path);\n\n            // Connect the client\n            Console.Write(\"Client connecting...\");\n            client.ConnectAsync();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Disconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client disconnecting...\");\n                    client.DisconnectAsync();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Send the entered text to the chat server\n                client.SendAsync(line);\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.DisconnectAndStop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: Simple protocol\nSimple protocol is defined in [simple.fbe](https://github.com/chronoxor/NetCoreServer/blob/master/proto/simple.fbe) file:\n\n```proto\n/*\n   Simple Fast Binary Encoding protocol for CppServer\n   https://github.com/chronoxor/FastBinaryEncoding\n\n   Generate protocol command: fbec --csharp --proto --input=simple.fbe --output=.\n*/\n\n// Domain declaration\ndomain com.chronoxor\n\n// Package declaration\npackage simple\n\n// Protocol version\nversion 1.0\n\n// Simple request message\n[request]\n[response(SimpleResponse)]\n[reject(SimpleReject)]\nmessage SimpleRequest\n{\n    // Request Id\n    uuid [id] = uuid1;\n    // Request message\n    string Message;\n}\n\n// Simple response\nmessage SimpleResponse\n{\n    // Response Id\n    uuid [id] = uuid1;\n    // Calculated message length\n    uint32 Length;\n    // Calculated message hash\n    uint32 Hash;\n}\n\n// Simple reject\nmessage SimpleReject\n{\n    // Reject Id\n    uuid [id] = uuid1;\n    // Error message\n    string Error;\n}\n\n// Simple notification\nmessage SimpleNotify\n{\n    // Server notification\n    string Notification;\n}\n\n// Disconnect request message\n[request]\nmessage DisconnectRequest\n{\n    // Request Id\n    uuid [id] = uuid1;\n}\n```\n\n## Example: Simple protocol server\nHere comes the example of  the  simple  protocol  server.  It  process  client\nrequests, answer with corresponding responses and  send  server  notifications\nback to clients.\n\n```c#\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing NetCoreServer;\n\nusing com.chronoxor.simple;\nusing com.chronoxor.simple.FBE;\n\nnamespace ProtoServer\n{\n    public class SimpleProtoSessionSender : Sender, ISenderListener\n    {\n        public SimpleProtoSession Session { get; }\n\n        public SimpleProtoSessionSender(SimpleProtoSession session) { Session = session; }\n\n        public long OnSend(byte[] buffer, long offset, long size)\n        {\n            return Session.SendAsync(buffer, offset, size) ? size : 0;\n        }\n    }\n\n    public class SimpleProtoSessionReceiver : Receiver, IReceiverListener\n    {\n        public SimpleProtoSession Session { get; }\n\n        public SimpleProtoSessionReceiver(SimpleProtoSession session) { Session = session; }\n\n        public void OnReceive(DisconnectRequest request) { Session.OnReceive(request); }\n        public void OnReceive(SimpleRequest request) { Session.OnReceive(request); }\n    }\n\n    public class SimpleProtoSession : TcpSession\n    {\n        public SimpleProtoSessionSender Sender { get; }\n        public SimpleProtoSessionReceiver Receiver { get; }\n\n        public SimpleProtoSession(TcpServer server) : base(server)\n        {\n            Sender = new SimpleProtoSessionSender(this);\n            Receiver = new SimpleProtoSessionReceiver(this);\n        }\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"TCP protocol session with Id '{Id}' connected to remote address '{(Socket.RemoteEndPoint as IPEndPoint)?.Address}' and port {(Socket.RemoteEndPoint as IPEndPoint)?.Port}\");\n\n            // Send invite notification\n            SimpleNotify notify = SimpleNotify.Default;\n            notify.Notification = \"Hello from Simple protocol server! Please send a message or '!' to disconnect the client!\";\n            Sender.Send(notify);\n        }\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"TCP protocol session with Id '{Id}' disconnected\");\n        }\n\n        protected override void OnReceived(byte[] buffer, long offset, long size)\n        {\n            Receiver.Receive(buffer, offset, size);\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"TCP protocol session with Id '{Id}' caught a socket error: {error}\");\n        }\n\n        // Protocol handlers\n        public void OnReceive(DisconnectRequest request) { Disconnect(); }\n        public void OnReceive(SimpleRequest request)\n        {\n            Console.WriteLine($\"Received: {request}\");\n\n            // Validate request\n            if (string.IsNullOrEmpty(request.Message))\n            {\n                // Send reject\n                SimpleReject reject = SimpleReject.Default;\n                reject.id = request.id;\n                reject.Error = \"Request message is empty!\";\n                Sender.Send(reject);\n                return;\n            }\n\n            // Send response\n            SimpleResponse response = SimpleResponse.Default;\n            response.id = request.id;\n            response.Hash = (uint)request.Message.GetHashCode();\n            response.Length = (uint)request.Message.Length;\n            Sender.Send(response);\n        }\n    }\n\n    public class SimpleProtoSender : Sender, ISenderListener\n    {\n        public SimpleProtoServer Server { get; }\n\n        public SimpleProtoSender(SimpleProtoServer server) { Server = server; }\n\n        public long OnSend(byte[] buffer, long offset, long size)\n        {\n            Server.Multicast(buffer, offset, size);\n            return size;\n        }\n    }\n\n    public class SimpleProtoServer : TcpServer\n    {\n        public SimpleProtoSender Sender { get; }\n\n        public SimpleProtoServer(IPAddress address, int port) : base(address, port)\n        {\n            Sender = new SimpleProtoSender(this);\n        }\n\n        protected override TcpSession CreateSession() { return new SimpleProtoSession(this); }\n\n        protected override void OnStarted()\n        {\n            Console.WriteLine($\"Simple protocol server with Id '{Id}' started!\");\n        }\n\n        protected override void OnStopped()\n        {\n            Console.WriteLine($\"Simple protocol server with Id '{Id}' stopped!\");\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Simple protocol server with Id '{Id}' caught an error: {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // Simple protocol server port\n            int port = 4444;\n            if (args.Length \u003e 0)\n                port = int.Parse(args[0]);\n\n            Console.WriteLine($\"Simple protocol server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create a new simple protocol server\n            var server = new SimpleProtoServer(IPAddress.Any, port);\n\n            // Start the server\n            Console.Write(\"Server starting...\");\n            server.Start();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Multicast admin notification to all sessions\n                SimpleNotify notify = SimpleNotify.Default;\n                notify.Notification = \"(admin) \" + line;\n                server.Sender.Send(notify);\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: Simple protocol client\nHere comes the example of the simple  protocol  client.  It  connects  to  the\nsimple protocol  server  and  allows  to  send  requests  to  it  and  receive\ncorresponding responses.\n\n```c#\nusing System;\nusing System.Net.Sockets;\nusing System.Threading;\nusing TcpClient = NetCoreServer.TcpClient;\n\nusing com.chronoxor.simple;\nusing com.chronoxor.simple.FBE;\n\nnamespace ProtoClient\n{\n    public class TcpProtoClient : TcpClient\n    {\n        public TcpProtoClient(string address, int port) : base(address, port) {}\n\n        public bool ConnectAndStart()\n        {\n            Console.WriteLine($\"TCP protocol client starting a new session with Id '{Id}'...\");\n\n            StartReconnectTimer();\n            return ConnectAsync();\n        }\n\n        public bool DisconnectAndStop()\n        {\n            Console.WriteLine($\"TCP protocol client stopping the session with Id '{Id}'...\");\n\n            StopReconnectTimer();\n            DisconnectAsync();\n            return true;\n        }\n\n        public override bool Reconnect()\n        {\n            return ReconnectAsync();\n        }\n\n        private Timer _reconnectTimer;\n\n        public void StartReconnectTimer()\n        {\n            // Start the reconnect timer\n            _reconnectTimer = new Timer(state =\u003e\n            {\n                Console.WriteLine($\"TCP reconnect timer connecting the client session with Id '{Id}'...\");\n                ConnectAsync();\n            }, null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);\n        }\n\n        public void StopReconnectTimer()\n        {\n            // Stop the reconnect timer\n            _reconnectTimer?.Dispose();\n            _reconnectTimer = null;\n        }\n\n        public delegate void ConnectedHandler();\n        public event ConnectedHandler Connected = () =\u003e {};\n\n        protected override void OnConnected()\n        {\n            Console.WriteLine($\"TCP protocol client connected a new session with Id '{Id}' to remote address '{Address}' and port {Port}\");\n\n            Connected?.Invoke();\n        }\n\n        public delegate void DisconnectedHandler();\n        public event DisconnectedHandler Disconnected = () =\u003e {};\n\n        protected override void OnDisconnected()\n        {\n            Console.WriteLine($\"TCP protocol client disconnected the session with Id '{Id}'\");\n\n            // Setup and asynchronously wait for the reconnect timer\n            _reconnectTimer?.Change(TimeSpan.FromSeconds(1), Timeout.InfiniteTimeSpan);\n\n            Disconnected?.Invoke();\n        }\n\n        public delegate void ReceivedHandler(byte[] buffer, long offset, long size);\n        public event ReceivedHandler Received = (buffer, offset, size) =\u003e {};\n\n        protected override void OnReceived(byte[] buffer, long offset, long size)\n        {\n            Received?.Invoke(buffer, offset, size);\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"TCP protocol client caught a socket error: {error}\");\n        }\n\n        #region IDisposable implementation\n\n        // Disposed flag.\n        private bool _disposed;\n\n        protected override void Dispose(bool disposingManagedResources)\n        {\n            if (!_disposed)\n            {\n                if (disposingManagedResources)\n                {\n                    // Dispose managed resources here...\n                    StopReconnectTimer();\n                }\n\n                // Dispose unmanaged resources here...\n\n                // Set large fields to null here...\n\n                // Mark as disposed.\n                _disposed = true;\n            }\n\n            // Call Dispose in the base class.\n            base.Dispose(disposingManagedResources);\n        }\n\n        // The derived class does not have a Finalize method\n        // or a Dispose method without parameters because it inherits\n        // them from the base class.\n\n        #endregion\n    }\n\n    public class SimpleProtoClient : Client, ISenderListener, IReceiverListener, IDisposable\n    {\n        private readonly TcpProtoClient _tcpProtoClient;\n\n        public Guid Id =\u003e _tcpProtoClient.Id;\n        public bool IsConnected =\u003e _tcpProtoClient.IsConnected;\n\n        public SimpleProtoClient(string address, int port)\n        {\n            _tcpProtoClient = new TcpProtoClient(address, port);\n            _tcpProtoClient.Connected += OnConnected;\n            _tcpProtoClient.Disconnected += OnDisconnected;\n            _tcpProtoClient.Received += OnReceived;\n            ReceivedResponse_DisconnectRequest += HandleDisconnectRequest;\n            ReceivedResponse_SimpleResponse += HandleSimpleResponse;\n            ReceivedResponse_SimpleReject += HandleSimpleReject;\n            ReceivedResponse_SimpleNotify += HandleSimpleNotify;\n        }\n\n        private void DisposeClient()\n        {\n            _tcpProtoClient.Connected -= OnConnected;\n            _tcpProtoClient.Connected -= OnDisconnected;\n            _tcpProtoClient.Received -= OnReceived;\n            ReceivedResponse_DisconnectRequest -= HandleDisconnectRequest;\n            ReceivedResponse_SimpleResponse -= HandleSimpleResponse;\n            ReceivedResponse_SimpleReject -= HandleSimpleReject;\n            ReceivedResponse_SimpleNotify -= HandleSimpleNotify;\n            _tcpProtoClient.Dispose();\n        }\n\n        public bool ConnectAndStart() { return _tcpProtoClient.ConnectAndStart(); }\n        public bool DisconnectAndStop() { return _tcpProtoClient.DisconnectAndStop(); }\n        public bool Reconnect() { return _tcpProtoClient.Reconnect(); }\n\n        private bool _watchdog;\n        private Thread _watchdogThread;\n\n        public bool StartWatchdog()\n        {\n            if (_watchdog)\n                return false;\n\n            Console.WriteLine(\"Watchdog thread starting...\");\n\n            // Start the watchdog thread\n            _watchdog = true;\n            _watchdogThread = new Thread(WatchdogThread);\n\n            Console.WriteLine(\"Watchdog thread started!\");\n\n            return true;\n        }\n\n        public bool StopWatchdog()\n        {\n            if (!_watchdog)\n                return false;\n\n            Console.WriteLine(\"Watchdog thread stopping...\");\n\n            // Stop the watchdog thread\n            _watchdog = false;\n            _watchdogThread.Join();\n\n            Console.WriteLine(\"Watchdog thread stopped!\");\n\n            return true;\n        }\n\n        public static void WatchdogThread(object obj)\n        {\n            var instance = obj as SimpleProtoClient;\n            if (instance == null)\n                return;\n\n            try\n            {\n                // Watchdog loop...\n                while (instance._watchdog)\n                {\n                    var utc = DateTime.UtcNow;\n\n                    // Watchdog the client\n                    instance.Watchdog(utc);\n\n                    // Sleep for a while...\n                    Thread.Sleep(1000);\n                }\n            }\n            catch (Exception e)\n            {\n                Console.WriteLine($\"Config client watchdog thread terminated: {e}\");\n            }\n        }\n\n        #region Connection handlers\n\n        public delegate void ConnectedHandler();\n        public event ConnectedHandler Connected = () =\u003e {};\n\n        private void OnConnected()\n        {\n            // Reset FBE protocol buffers\n            Reset();\n\n            Connected?.Invoke();\n        }\n\n        public delegate void DisconnectedHandler();\n        public event DisconnectedHandler Disconnected = () =\u003e {};\n\n        private void OnDisconnected()\n        {\n            Disconnected?.Invoke();\n        }\n\n        public long OnSend(byte[] buffer, long offset, long size)\n        {\n            return _tcpProtoClient.SendAsync(buffer, offset, size) ? size : 0;\n        }\n\n        public void OnReceived(byte[] buffer, long offset, long size)\n        {\n            Receive(buffer, offset, size);\n        }\n\n        #endregion\n\n        #region Protocol handlers\n\n        private void HandleDisconnectRequest(DisconnectRequest request) { Console.WriteLine($\"Received: {request}\"); _tcpProtoClient.DisconnectAsync(); }\n        private void HandleSimpleResponse(SimpleResponse response) { Console.WriteLine($\"Received: {response}\"); }\n        private void HandleSimpleReject(SimpleReject reject) { Console.WriteLine($\"Received: {reject}\"); }\n        private void HandleSimpleNotify(SimpleNotify notify) { Console.WriteLine($\"Received: {notify}\"); }\n\n        #endregion\n\n        #region IDisposable implementation\n\n        // Disposed flag.\n        private bool _disposed;\n\n        // Implement IDisposable.\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        protected virtual void Dispose(bool disposingManagedResources)\n        {\n            // The idea here is that Dispose(Boolean) knows whether it is\n            // being called to do explicit cleanup (the Boolean is true)\n            // versus being called due to a garbage collection (the Boolean\n            // is false). This distinction is useful because, when being\n            // disposed explicitly, the Dispose(Boolean) method can safely\n            // execute code using reference type fields that refer to other\n            // objects knowing for sure that these other objects have not been\n            // finalized or disposed of yet. When the Boolean is false,\n            // the Dispose(Boolean) method should not execute code that\n            // refer to reference type fields because those objects may\n            // have already been finalized.\"\n\n            if (!_disposed)\n            {\n                if (disposingManagedResources)\n                {\n                    // Dispose managed resources here...\n                    DisposeClient();\n                }\n\n                // Dispose unmanaged resources here...\n\n                // Set large fields to null here...\n\n                // Mark as disposed.\n                _disposed = true;\n            }\n        }\n\n        #endregion\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // Simple protocol server address\n            string address = \"127.0.0.1\";\n            if (args.Length \u003e 0)\n                address = args[0];\n\n            // Simple protocol server port\n            int port = 4444;\n            if (args.Length \u003e 1)\n                port = int.Parse(args[1]);\n\n            Console.WriteLine($\"Simple protocol server address: {address}\");\n            Console.WriteLine($\"Simple protocol server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create a new simple protocol chat client\n            var client = new SimpleProtoClient(address, port);\n\n            // Connect the client\n            Console.Write(\"Client connecting...\");\n            client.ConnectAndStart();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Disconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client disconnecting...\");\n                    client.Reconnect();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Send request to the simple protocol server\n                SimpleRequest request = SimpleRequest.Default;\n                request.Message = line;\n                var response = client.Request(request).Result;\n\n                // Show string hash calculation result\n                Console.WriteLine($\"Hash of '{line}' = 0x{response.Hash:X8}\");\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.DisconnectAndStop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: HTTP server\nHere comes the example of the HTTP cache server. It allows to manipulate\ncache data with HTTP methods (GET, POST, PUT and DELETE).\n\nUse the following link to open [Swagger OpenAPI](https://swagger.io/specification/) iterative documentation: http://localhost:8080/api/index.html\n\n![OpenAPI-HTTP](https://github.com/chronoxor/NetCoreServer/raw/master/images/openapi-http.png)\n\n```c#\nusing System;\nusing System.Collections.Concurrent;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\nusing NetCoreServer;\n\nnamespace HttpServer\n{\n    class CommonCache\n    {\n        public static CommonCache GetInstance()\n        {\n            if (_instance == null)\n                _instance = new CommonCache();\n            return _instance;\n        }\n\n        public string GetAllCache()\n        {\n            var result = new StringBuilder();\n            result.Append(\"[\\n\");\n            foreach (var item in _cache)\n            {\n                result.Append(\"  {\\n\");\n                result.AppendFormat($\"    \\\"key\\\": \\\"{item.Key}\\\",\\n\");\n                result.AppendFormat($\"    \\\"value\\\": \\\"{item.Value}\\\",\\n\");\n                result.Append(\"  },\\n\");\n            }\n            result.Append(\"]\\n\");\n            return result.ToString();\n        }\n\n        public bool GetCacheValue(string key, out string value)\n        {\n            return _cache.TryGetValue(key, out value);\n        }\n\n        public void PutCacheValue(string key, string value)\n        {\n            _cache[key] = value;\n        }\n\n        public bool DeleteCacheValue(string key, out string value)\n        {\n            return _cache.TryRemove(key, out value);\n        }\n\n        private readonly ConcurrentDictionary\u003cstring, string\u003e _cache = new ConcurrentDictionary\u003cstring, string\u003e();\n        private static CommonCache _instance;\n    }\n\n    class HttpCacheSession : HttpSession\n    {\n        public HttpCacheSession(NetCoreServer.HttpServer server) : base(server) {}\n\n        protected override void OnReceivedRequest(HttpRequest request)\n        {\n            // Show HTTP request content\n            Console.WriteLine(request);\n\n            // Process HTTP request methods\n            if (request.Method == \"HEAD\")\n                SendResponseAsync(Response.MakeHeadResponse());\n            else if (request.Method == \"GET\")\n            {\n                string key = request.Url;\n\n                // Decode the key value\n                key = Uri.UnescapeDataString(key);\n                key = key.Replace(\"/api/cache\", \"\", StringComparison.InvariantCultureIgnoreCase);\n                key = key.Replace(\"?key=\", \"\", StringComparison.InvariantCultureIgnoreCase);\n\n                if (string.IsNullOrEmpty(key))\n                {\n                    // Response with all cache values\n                    SendResponseAsync(Response.MakeGetResponse(CommonCache.GetInstance().GetAllCache(), \"application/json; charset=UTF-8\"));\n                }\n                // Get the cache value by the given key\n                else if (CommonCache.GetInstance().GetCacheValue(key, out var value))\n                {\n                    // Response with the cache value\n                    SendResponseAsync(Response.MakeGetResponse(value));\n                }\n                else\n                    SendResponseAsync(Response.MakeErrorResponse(404, \"Required cache value was not found for the key: \" + key));\n            }\n            else if ((request.Method == \"POST\") || (request.Method == \"PUT\"))\n            {\n                string key = request.Url;\n                string value = request.Body;\n\n                // Decode the key value\n                key = Uri.UnescapeDataString(key);\n                key = key.Replace(\"/api/cache\", \"\", StringComparison.InvariantCultureIgnoreCase);\n                key = key.Replace(\"?key=\", \"\", StringComparison.InvariantCultureIgnoreCase);\n\n                // Put the cache value\n                CommonCache.GetInstance().PutCacheValue(key, value);\n\n                // Response with the cache value\n                SendResponseAsync(Response.MakeOkResponse());\n            }\n            else if (request.Method == \"DELETE\")\n            {\n                string key = request.Url;\n\n                // Decode the key value\n                key = Uri.UnescapeDataString(key);\n                key = key.Replace(\"/api/cache\", \"\", StringComparison.InvariantCultureIgnoreCase);\n                key = key.Replace(\"?key=\", \"\", StringComparison.InvariantCultureIgnoreCase);\n\n                // Delete the cache value\n                if (CommonCache.GetInstance().DeleteCacheValue(key, out var value))\n                {\n                    // Response with the cache value\n                    SendResponseAsync(Response.MakeGetResponse(value));\n                }\n                else\n                    SendResponseAsync(Response.MakeErrorResponse(404, \"Deleted cache value was not found for the key: \" + key));\n            }\n            else if (request.Method == \"OPTIONS\")\n                SendResponseAsync(Response.MakeOptionsResponse());\n            else if (request.Method == \"TRACE\")\n                SendResponseAsync(Response.MakeTraceResponse(request.Cache.Data));\n            else\n                SendResponseAsync(Response.MakeErrorResponse(\"Unsupported HTTP method: \" + request.Method));\n        }\n\n        protected override void OnReceivedRequestError(HttpRequest request, string error)\n        {\n            Console.WriteLine($\"Request error: {error}\");\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"HTTP session caught an error: {error}\");\n        }\n    }\n\n    class HttpCacheServer : NetCoreServer.HttpServer\n    {\n        public HttpCacheServer(IPAddress address, int port) : base(address, port) {}\n\n        protected override TcpSession CreateSession() { return new HttpCacheSession(this); }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"HTTP session caught an error: {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // HTTP server port\n            int port = 8080;\n            if (args.Length \u003e 0)\n                port = int.Parse(args[0]);\n            // HTTP server content path\n            string www = \"../../../../../www/api\";\n            if (args.Length \u003e 1)\n                www = args[1];\n\n            Console.WriteLine($\"HTTP server port: {port}\");\n            Console.WriteLine($\"HTTP server static content path: {www}\");\n            Console.WriteLine($\"HTTP server website: http://localhost:{port}/api/index.html\");\n\n            Console.WriteLine();\n\n            // Create a new HTTP server\n            var server = new HttpCacheServer(IPAddress.Any, port);\n            server.AddStaticContent(www, \"/api\");\n\n            // Start the server\n            Console.Write(\"Server starting...\");\n            server.Start();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                }\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: HTTP client\nHere comes the example of the HTTP client. It allows to send HTTP requests\n(GET, POST, PUT and DELETE) and receive HTTP responses.\n\n```c#\nusing System;\nusing NetCoreServer;\n\nnamespace HttpClient\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // HTTP server address\n            string address = \"127.0.0.1\";\n            if (args.Length \u003e 0)\n                address = args[0];\n\n            // HTTP server port\n            int port = 8080;\n            if (args.Length \u003e 1)\n                port = int.Parse(args[1]);\n\n            Console.WriteLine($\"HTTP server address: {address}\");\n            Console.WriteLine($\"HTTP server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create a new HTTP client\n            var client = new HttpClientEx(address, port);\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Reconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client reconnecting...\");\n                    if (client.IsConnected)\n                        client.ReconnectAsync();\n                    else\n                        client.ConnectAsync();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                var commands = line.Split(' ');\n                if (commands.Length \u003c 2)\n                {\n                    Console.WriteLine(\"HTTP method and URL must be entered!\");\n                    continue;\n                }\n\n                if (commands[0].ToUpper() == \"HEAD\")\n                {\n                    var response = client.SendHeadRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"GET\")\n                {\n                    var response = client.SendGetRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"POST\")\n                {\n                    if (commands.Length \u003c 3)\n                    {\n                        Console.WriteLine(\"HTTP method, URL and body must be entered!\");\n                        continue;\n                    }\n\n                    var response = client.SendPostRequest(commands[1], commands[2]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"PUT\")\n                {\n                    if (commands.Length \u003c 3)\n                    {\n                        Console.WriteLine(\"HTTP method, URL and body must be entered!\");\n                        continue;\n                    }\n\n                    var response = client.SendPutRequest(commands[1], commands[2]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"DELETE\")\n                {\n                    var response = client.SendDeleteRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"OPTIONS\")\n                {\n                    var response = client.SendOptionsRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"TRACE\")\n                {\n                    var response = client.SendTraceRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else\n                    Console.WriteLine(\"Unknown HTTP method\");\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.Disconnect();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: HTTPS server\nHere comes the example of the HTTPS cache server. It allows to manipulate\ncache data with HTTP methods (GET, POST, PUT and DELETE) with secured\ntransport protocol.\n\nUse the following link to open [Swagger OpenAPI](https://swagger.io/specification/) iterative documentation: https://localhost:8443/api/index.html\n\n![OpenAPI-HTTPS](https://github.com/chronoxor/NetCoreServer/raw/master/images/openapi-https.png)\n\n```c#\nusing System;\nusing System.Collections.Concurrent;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Text;\nusing NetCoreServer;\n\nnamespace HttpsServer\n{\n    class CommonCache\n    {\n        public static CommonCache GetInstance()\n        {\n            if (_instance == null)\n                _instance = new CommonCache();\n            return _instance;\n        }\n\n        public string GetAllCache()\n        {\n            var result = new StringBuilder();\n            result.Append(\"[\\n\");\n            foreach (var item in _cache)\n            {\n                result.Append(\"  {\\n\");\n                result.AppendFormat($\"    \\\"key\\\": \\\"{item.Key}\\\",\\n\");\n                result.AppendFormat($\"    \\\"value\\\": \\\"{item.Value}\\\",\\n\");\n                result.Append(\"  },\\n\");\n            }\n            result.Append(\"]\\n\");\n            return result.ToString();\n        }\n\n        public bool GetCacheValue(string key, out string value)\n        {\n            return _cache.TryGetValue(key, out value);\n        }\n\n        public void PutCacheValue(string key, string value)\n        {\n            _cache[key] = value;\n        }\n\n        public bool DeleteCacheValue(string key, out string value)\n        {\n            return _cache.TryRemove(key, out value);\n        }\n\n        private readonly ConcurrentDictionary\u003cstring, string\u003e _cache = new ConcurrentDictionary\u003cstring, string\u003e();\n        private static CommonCache _instance;\n    }\n\n    class HttpsCacheSession : HttpsSession\n    {\n        public HttpsCacheSession(NetCoreServer.HttpsServer server) : base(server) {}\n\n        protected override void OnReceivedRequest(HttpRequest request)\n        {\n            // Show HTTP request content\n            Console.WriteLine(request);\n\n            // Process HTTP request methods\n            if (request.Method == \"HEAD\")\n                SendResponseAsync(Response.MakeHeadResponse());\n            else if (request.Method == \"GET\")\n            {\n                string key = request.Url;\n\n                // Decode the key value\n                key = Uri.UnescapeDataString(key);\n                key = key.Replace(\"/api/cache\", \"\", StringComparison.InvariantCultureIgnoreCase);\n                key = key.Replace(\"?key=\", \"\", StringComparison.InvariantCultureIgnoreCase);\n\n                if (string.IsNullOrEmpty(key))\n                {\n                    // Response with all cache values\n                    SendResponseAsync(Response.MakeGetResponse(CommonCache.GetInstance().GetAllCache(), \"application/json; charset=UTF-8\"));\n                }\n                // Get the cache value by the given key\n                else if (CommonCache.GetInstance().GetCacheValue(key, out var value))\n                {\n                    // Response with the cache value\n                    SendResponseAsync(Response.MakeGetResponse(value));\n                }\n                else\n                    SendResponseAsync(Response.MakeErrorResponse(404, \"Required cache value was not found for the key: \" + key));\n            }\n            else if ((request.Method == \"POST\") || (request.Method == \"PUT\"))\n            {\n                string key = request.Url;\n                string value = request.Body;\n\n                // Decode the key value\n                key = Uri.UnescapeDataString(key);\n                key = key.Replace(\"/api/cache\", \"\", StringComparison.InvariantCultureIgnoreCase);\n                key = key.Replace(\"?key=\", \"\", StringComparison.InvariantCultureIgnoreCase);\n\n                // Put the cache value\n                CommonCache.GetInstance().PutCacheValue(key, value);\n\n                // Response with the cache value\n                SendResponseAsync(Response.MakeOkResponse());\n            }\n            else if (request.Method == \"DELETE\")\n            {\n                string key = request.Url;\n\n                // Decode the key value\n                key = Uri.UnescapeDataString(key);\n                key = key.Replace(\"/api/cache\", \"\", StringComparison.InvariantCultureIgnoreCase);\n                key = key.Replace(\"?key=\", \"\", StringComparison.InvariantCultureIgnoreCase);\n\n                // Delete the cache value\n                if (CommonCache.GetInstance().DeleteCacheValue(key, out var value))\n                {\n                    // Response with the cache value\n                    SendResponseAsync(Response.MakeGetResponse(value));\n                }\n                else\n                    SendResponseAsync(Response.MakeErrorResponse(404, \"Deleted cache value was not found for the key: \" + key));\n            }\n            else if (request.Method == \"OPTIONS\")\n                SendResponseAsync(Response.MakeOptionsResponse());\n            else if (request.Method == \"TRACE\")\n                SendResponseAsync(Response.MakeTraceResponse(request.Cache));\n            else\n                SendResponseAsync(Response.MakeErrorResponse(\"Unsupported HTTP method: \" + request.Method));\n        }\n\n        protected override void OnReceivedRequestError(HttpRequest request, string error)\n        {\n            Console.WriteLine($\"Request error: {error}\");\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"HTTPS session caught an error: {error}\");\n        }\n    }\n\n    class HttpsCacheServer : NetCoreServer.HttpsServer\n    {\n        public HttpsCacheServer(SslContext context, IPAddress address, int port) : base(context, address, port) {}\n\n        protected override SslSession CreateSession() { return new HttpsCacheSession(this); }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"HTTPS server caught an error: {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // HTTPS server port\n            int port = 8443;\n            if (args.Length \u003e 0)\n                port = int.Parse(args[0]);\n            // HTTPS server content path\n            string www = \"../../../../../www/api\";\n            if (args.Length \u003e 1)\n                www = args[1];\n\n            Console.WriteLine($\"HTTPS server port: {port}\");\n            Console.WriteLine($\"HTTPS server static content path: {www}\");\n            Console.WriteLine($\"HTTPS server website: https://localhost:{port}/api/index.html\");\n\n            Console.WriteLine();\n\n            // Create and prepare a new SSL server context\n            var context = new SslContext(SslProtocols.Tls12, new X509Certificate2(\"server.pfx\", \"qwerty\"));\n\n            // Create a new HTTP server\n            var server = new HttpsCacheServer(context, IPAddress.Any, port);\n            server.AddStaticContent(www, \"/api\");\n\n            // Start the server\n            Console.Write(\"Server starting...\");\n            server.Start();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                }\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: HTTPS client\nHere comes the example of the HTTPS client. It allows to send HTTP requests\n(GET, POST, PUT and DELETE) and receive HTTP responses with secured\ntransport protocol.\n\n```c#\nusing System;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\nusing NetCoreServer;\n\nnamespace HttpsClient\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // HTTPS server address\n            string address = \"127.0.0.1\";\n            if (args.Length \u003e 0)\n                address = args[0];\n\n            // HTTPS server port\n            int port = 8443;\n            if (args.Length \u003e 1)\n                port = int.Parse(args[1]);\n\n            Console.WriteLine($\"HTTPS server address: {address}\");\n            Console.WriteLine($\"HTTPS server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create and prepare a new SSL client context\n            var context = new SslContext(SslProtocols.Tls12, new X509Certificate2(\"client.pfx\", \"qwerty\"), (sender, certificate, chain, sslPolicyErrors) =\u003e true);\n\n            // Create a new HTTPS client\n            var client = new HttpsClientEx(context, address, port);\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Reconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client reconnecting...\");\n                    if (client.IsConnected)\n                        client.ReconnectAsync();\n                    else\n                        client.ConnectAsync();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                var commands = line.Split(' ');\n                if (commands.Length \u003c 2)\n                {\n                    Console.WriteLine(\"HTTP method and URL must be entered!\");\n                    continue;\n                }\n\n                if (commands[0].ToUpper() == \"HEAD\")\n                {\n                    var response = client.SendHeadRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"GET\")\n                {\n                    var response = client.SendGetRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"POST\")\n                {\n                    if (commands.Length \u003c 3)\n                    {\n                        Console.WriteLine(\"HTTP method, URL and body must be entered!\");\n                        continue;\n                    }\n\n                    var response = client.SendPostRequest(commands[1], commands[2]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"PUT\")\n                {\n                    if (commands.Length \u003c 3)\n                    {\n                        Console.WriteLine(\"HTTP method, URL and body must be entered!\");\n                        continue;\n                    }\n\n                    var response = client.SendPutRequest(commands[1], commands[2]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"DELETE\")\n                {\n                    var response = client.SendDeleteRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"OPTIONS\")\n                {\n                    var response = client.SendOptionsRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else if (commands[0].ToUpper() == \"TRACE\")\n                {\n                    var response = client.SendTraceRequest(commands[1]).Result;\n                    Console.WriteLine(response);\n                }\n                else\n                    Console.WriteLine(\"Unknown HTTP method\");\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.Disconnect();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: WebSocket chat server\nHere comes the example of the WebSocket chat server. It handles multiple\nWebSocket client sessions and multicast received message from any session\nto all ones. Also it is possible to send admin message directly from the\nserver.\n\nUse the following link to open WebSocket chat server example: http://localhost:8080/chat/index.html\n\n![ws-chat](https://github.com/chronoxor/NetCoreServer/raw/master/images/ws-chat.png)\n\n```c#\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\nusing NetCoreServer;\n\nnamespace WsChatServer\n{\n    class ChatSession : WsSession\n    {\n        public ChatSession(WsServer server) : base(server) {}\n\n        public override void OnWsConnected(HttpRequest request)\n        {\n            Console.WriteLine($\"Chat WebSocket session with Id {Id} connected!\");\n\n            // Send invite message\n            string message = \"Hello from WebSocket chat! Please send a message or '!' to disconnect the client!\";\n            SendTextAsync(message);\n        }\n\n        public override void OnWsDisconnected()\n        {\n            Console.WriteLine($\"Chat WebSocket session with Id {Id} disconnected!\");\n        }\n\n        public override void OnWsReceived(byte[] buffer, long offset, long size)\n        {\n            string message = Encoding.UTF8.GetString(buffer, (int)offset, (int)size);\n            Console.WriteLine(\"Incoming: \" + message);\n\n            // Multicast message to all connected sessions\n            ((WsServer)Server).MulticastText(message);\n\n            // If the buffer starts with '!' the disconnect the current session\n            if (message == \"!\")\n                Close(1000);\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat WebSocket session caught an error with code {error}\");\n        }\n    }\n\n    class ChatServer : WsServer\n    {\n        public ChatServer(IPAddress address, int port) : base(address, port) {}\n\n        protected override TcpSession CreateSession() { return new ChatSession(this); }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat WebSocket server caught an error with code {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // WebSocket server port\n            int port = 8080;\n            if (args.Length \u003e 0)\n                port = int.Parse(args[0]);\n            // WebSocket server content path\n            string www = \"../../../../../www/ws\";\n            if (args.Length \u003e 1)\n                www = args[1];\n\n            Console.WriteLine($\"WebSocket server port: {port}\");\n            Console.WriteLine($\"WebSocket server static content path: {www}\");\n            Console.WriteLine($\"WebSocket server website: http://localhost:{port}/chat/index.html\");\n\n            Console.WriteLine();\n\n            // Create a new WebSocket server\n            var server = new ChatServer(IPAddress.Any, port);\n            server.AddStaticContent(www, \"/chat\");\n\n            // Start the server\n            Console.Write(\"Server starting...\");\n            server.Start();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                }\n\n                // Multicast admin message to all sessions\n                line = \"(admin) \" + line;\n                server.MulticastText(line);\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: WebSocket chat client\nHere comes the example of the WebSocket chat client. It connects to the\nWebSocket chat server and allows to send message to it and receive new\nmessages.\n\n```c#\nusing System;\nusing System.Net.Sockets;\nusing System.Text;\nusing System.Threading;\nusing NetCoreServer;\n\nnamespace WsChatClient\n{\n    class ChatClient : WsClient\n    {\n        public ChatClient(string address, int port) : base(address, port) {}\n\n        public void DisconnectAndStop()\n        {\n            _stop = true;\n            CloseAsync(1000);\n            while (IsConnected)\n                Thread.Yield();\n        }\n\n        public override void OnWsConnecting(HttpRequest request)\n        {\n            request.SetBegin(\"GET\", \"/\");\n            request.SetHeader(\"Host\", \"localhost\");\n            request.SetHeader(\"Origin\", \"http://localhost\");\n            request.SetHeader(\"Upgrade\", \"websocket\");\n            request.SetHeader(\"Connection\", \"Upgrade\");\n            request.SetHeader(\"Sec-WebSocket-Key\", Convert.ToBase64String(WsNonce));\n            request.SetHeader(\"Sec-WebSocket-Protocol\", \"chat, superchat\");\n            request.SetHeader(\"Sec-WebSocket-Version\", \"13\");\n            request.SetBody();\n        }\n\n        public override void OnWsConnected(HttpResponse response)\n        {\n            Console.WriteLine($\"Chat WebSocket client connected a new session with Id {Id}\");\n        }\n\n        public override void OnWsDisconnected()\n        {\n            Console.WriteLine($\"Chat WebSocket client disconnected a session with Id {Id}\");\n        }\n\n        public override void OnWsReceived(byte[] buffer, long offset, long size)\n        {\n            Console.WriteLine($\"Incoming: {Encoding.UTF8.GetString(buffer, (int)offset, (int)size)}\");\n        }\n\n        protected override void OnDisconnected()\n        {\n            base.OnDisconnected();\n\n            Console.WriteLine($\"Chat WebSocket client disconnected a session with Id {Id}\");\n\n            // Wait for a while...\n            Thread.Sleep(1000);\n\n            // Try to connect again\n            if (!_stop)\n                ConnectAsync();\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat WebSocket client caught an error with code {error}\");\n        }\n\n        private bool _stop;\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // WebSocket server address\n            string address = \"127.0.0.1\";\n            if (args.Length \u003e 0)\n                address = args[0];\n\n            // WebSocket server port\n            int port = 8080;\n            if (args.Length \u003e 1)\n                port = int.Parse(args[1]);\n\n            Console.WriteLine($\"WebSocket server address: {address}\");\n            Console.WriteLine($\"WebSocket server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create a new TCP chat client\n            var client = new ChatClient(address, port);\n\n            // Connect the client\n            Console.Write(\"Client connecting...\");\n            client.ConnectAsync();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Disconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client disconnecting...\");\n                    client.DisconnectAsync();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Send the entered text to the chat server\n                client.SendTextAsync(line);\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.DisconnectAndStop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: WebSocket secure chat server\nHere comes the example of the WebSocket secure chat server. It handles\nmultiple WebSocket secure client sessions and multicast received message\nfrom any session to all ones. Also it is possible to send admin message\ndirectly from the server.\n\nThis example is very similar to the WebSocket one except the code that\nprepares WebSocket secure context and handshake handler.\n\nUse the following link to open WebSocket secure chat server example: https://localhost:8443/chat/index.html\n\n![wss-chat](https://github.com/chronoxor/NetCoreServer/raw/master/images/wss-chat.png)\n\n```c#\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Text;\nusing NetCoreServer;\n\nnamespace WssChatServer\n{\n    class ChatSession : WssSession\n    {\n        public ChatSession(WssServer server) : base(server) {}\n\n        public override void OnWsConnected(HttpRequest request)\n        {\n            Console.WriteLine($\"Chat WebSocket session with Id {Id} connected!\");\n\n            // Send invite message\n            string message = \"Hello from WebSocket chat! Please send a message or '!' to disconnect the client!\";\n            SendTextAsync(message);\n        }\n\n        public override void OnWsDisconnected()\n        {\n            Console.WriteLine($\"Chat WebSocket session with Id {Id} disconnected!\");\n        }\n\n        public override void OnWsReceived(byte[] buffer, long offset, long size)\n        {\n            string message = Encoding.UTF8.GetString(buffer, (int)offset, (int)size);\n            Console.WriteLine(\"Incoming: \" + message);\n\n            // Multicast message to all connected sessions\n            ((WssServer)Server).MulticastText(message);\n\n            // If the buffer starts with '!' the disconnect the current session\n            if (message == \"!\")\n                Close(1000);\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat WebSocket session caught an error with code {error}\");\n        }\n    }\n\n    class ChatServer : WssServer\n    {\n        public ChatServer(SslContext context, IPAddress address, int port) : base(context, address, port) {}\n\n        protected override SslSession CreateSession() { return new ChatSession(this); }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat WebSocket server caught an error with code {error}\");\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // WebSocket server port\n            int port = 8443;\n            if (args.Length \u003e 0)\n                port = int.Parse(args[0]);\n            // WebSocket server content path\n            string www = \"../../../../../www/wss\";\n            if (args.Length \u003e 1)\n                www = args[1];\n\n            Console.WriteLine($\"WebSocket server port: {port}\");\n            Console.WriteLine($\"WebSocket server static content path: {www}\");\n            Console.WriteLine($\"WebSocket server website: https://localhost:{port}/chat/index.html\");\n\n            Console.WriteLine();\n\n            // Create and prepare a new SSL server context\n            var context = new SslContext(SslProtocols.Tls12, new X509Certificate2(\"server.pfx\", \"qwerty\"));\n\n            // Create a new WebSocket server\n            var server = new ChatServer(context, IPAddress.Any, port);\n            server.AddStaticContent(www, \"/chat\");\n\n            // Start the server\n            Console.Write(\"Server starting...\");\n            server.Start();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the server or '!' to restart the server...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Restart the server\n                if (line == \"!\")\n                {\n                    Console.Write(\"Server restarting...\");\n                    server.Restart();\n                    Console.WriteLine(\"Done!\");\n                }\n\n                // Multicast admin message to all sessions\n                line = \"(admin) \" + line;\n                server.MulticastText(line);\n            }\n\n            // Stop the server\n            Console.Write(\"Server stopping...\");\n            server.Stop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n## Example: WebSocket secure chat client\nHere comes the example of the WebSocket secure chat client. It connects to\nthe WebSocket secure chat server and allows to send message to it and receive\nnew messages.\n\nThis example is very similar to the WebSocket one except the code that\nprepares WebSocket secure context and handshake handler.\n\n```c#\nusing System;\nusing System.Net.Sockets;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Text;\nusing System.Threading;\nusing NetCoreServer;\n\nnamespace WssChatClient\n{\n    class ChatClient : WssClient\n    {\n        public ChatClient(SslContext context, string address, int port) : base(context, address, port) {}\n\n        public void DisconnectAndStop()\n        {\n            _stop = true;\n            CloseAsync(1000);\n            while (IsConnected)\n                Thread.Yield();\n        }\n\n        public override void OnWsConnecting(HttpRequest request)\n        {\n            request.SetBegin(\"GET\", \"/\");\n            request.SetHeader(\"Host\", \"localhost\");\n            request.SetHeader(\"Origin\", \"http://localhost\");\n            request.SetHeader(\"Upgrade\", \"websocket\");\n            request.SetHeader(\"Connection\", \"Upgrade\");\n            request.SetHeader(\"Sec-WebSocket-Key\", Convert.ToBase64String(WsNonce));\n            request.SetHeader(\"Sec-WebSocket-Protocol\", \"chat, superchat\");\n            request.SetHeader(\"Sec-WebSocket-Version\", \"13\");\n            request.SetBody();\n        }\n\n        public override void OnWsConnected(HttpResponse response)\n        {\n            Console.WriteLine($\"Chat WebSocket client connected a new session with Id {Id}\");\n        }\n\n        public override void OnWsDisconnected()\n        {\n            Console.WriteLine($\"Chat WebSocket client disconnected a session with Id {Id}\");\n        }\n\n        public override void OnWsReceived(byte[] buffer, long offset, long size)\n        {\n            Console.WriteLine($\"Incoming: {Encoding.UTF8.GetString(buffer, (int)offset, (int)size)}\");\n        }\n\n        protected override void OnDisconnected()\n        {\n            base.OnDisconnected();\n\n            Console.WriteLine($\"Chat WebSocket client disconnected a session with Id {Id}\");\n\n            // Wait for a while...\n            Thread.Sleep(1000);\n\n            // Try to connect again\n            if (!_stop)\n                ConnectAsync();\n        }\n\n        protected override void OnError(SocketError error)\n        {\n            Console.WriteLine($\"Chat WebSocket client caught an error with code {error}\");\n        }\n\n        private bool _stop;\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            // WebSocket server address\n            string address = \"127.0.0.1\";\n            if (args.Length \u003e 0)\n                address = args[0];\n\n            // WebSocket server port\n            int port = 8443;\n            if (args.Length \u003e 1)\n                port = int.Parse(args[1]);\n\n            Console.WriteLine($\"WebSocket server address: {address}\");\n            Console.WriteLine($\"WebSocket server port: {port}\");\n\n            Console.WriteLine();\n\n            // Create and prepare a new SSL client context\n            var context = new SslContext(SslProtocols.Tls12, new X509Certificate2(\"client.pfx\", \"qwerty\"), (sender, certificate, chain, sslPolicyErrors) =\u003e true);\n\n            // Create a new TCP chat client\n            var client = new ChatClient(context, address, port);\n\n            // Connect the client\n            Console.Write(\"Client connecting...\");\n            client.ConnectAsync();\n            Console.WriteLine(\"Done!\");\n\n            Console.WriteLine(\"Press Enter to stop the client or '!' to reconnect the client...\");\n\n            // Perform text input\n            for (;;)\n            {\n                string line = Console.ReadLine();\n                if (string.IsNullOrEmpty(line))\n                    break;\n\n                // Reconnect the client\n                if (line == \"!\")\n                {\n                    Console.Write(\"Client reconnecting...\");\n                    if (client.IsConnected)\n                        client.ReconnectAsync();\n                    else\n                        client.ConnectAsync();\n                    Console.WriteLine(\"Done!\");\n                    continue;\n                }\n\n                // Send the entered text to the chat server\n                client.SendTextAsync(line);\n            }\n\n            // Disconnect the client\n            Console.Write(\"Client disconnecting...\");\n            client.DisconnectAndStop();\n            Console.WriteLine(\"Done!\");\n        }\n    }\n}\n```\n\n# Performance\n\nHere comes several communication scenarios with timing measurements.\n\nBenchmark environment is the following:\n```\nCPU architecutre: Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz\nCPU logical cores: 8\nCPU physical cores: 4\nCPU clock speed: 3.998 GHz\nCPU Hyper-Threading: enabled\nRAM total: 31.962 GiB\nRAM free: 24.011 GiB\n\nOS version: Microsoft Windows 8 Enterprise Edition (build 9200), 64-bit\nOS bits: 64-bit\nProcess bits: 64-bit\nProcess configuaraion: release\n```\n\n## Benchmark: Round-Trip\n\n![Round-trip](https://github.com/chronoxor/NetCoreServer/raw/master/images/round-trip.png)\n\nThis scenario sends lots of messages from several clients to a server.\nThe server responses to each message and resend the similar response to\nthe client. The benchmark measures total round-trip time to send all\nmessages and receive all responses, messages \u0026 data throughput, count\nof errors.\n\n### TCP echo server\n\n* [TcpEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/TcpEchoServer/Program.cs)\n* [TcpEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/TcpEchoClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 1111\nWorking clients: 1\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.024 s\nTotal data: 2.831 GiB\nTotal messages: 94369133\nData throughput: 287.299 MiB/s\nMessage latency: 106 ns\nMessage throughput: 9413997 msg/s\n```\n\n* [TcpEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/TcpEchoServer/Program.cs)\n* [TcpEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/TcpEchoClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 1111\nWorking clients: 100\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.189 s\nTotal data: 1.794 GiB\nTotal messages: 59585544\nData throughput: 178.463 MiB/s\nMessage latency: 171 ns\nMessage throughput: 5847523 msg/s\n```\n\n### SSL echo server\n\n* [SslEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/SslEchoServer/Program.cs)\n* [SslEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/SslEchoClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 2222\nWorking clients: 1\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 2.645 s\nTotal data: 373.329 MiB\nTotal messages: 12233021\nData throughput: 141.095 MiB/s\nMessage latency: 216 ns\nMessage throughput: 4623352 msg/s\n```\n\n* [SslEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/SslEchoServer/Program.cs)\n* [SslEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/SslEchoClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 2222\nWorking clients: 100\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.060 s\nTotal data: 1.472 GiB\nTotal messages: 49029133\nData throughput: 148.741 MiB/s\nMessage latency: 205 ns\nMessage throughput: 4873398 msg/s\n```\n\n### UDP echo server\n\n* [UdpEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdpEchoServer/Program.cs)\n* [UdpEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdpEchoClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 3333\nWorking clients: 1\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.032 s\nTotal data: 33.994 MiB\nTotal messages: 1113182\nData throughput: 3.395 MiB/s\nMessage latency: 9.012 mcs\nMessage throughput: 110960 msg/s\n```\n\n* [UdpEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdpEchoServer/Program.cs)\n* [UdpEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdpEchoClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 3333\nWorking clients: 100\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.635 s\nTotal data: 20.355 MiB\nTotal messages: 666791\nData throughput: 1.934 MiB/s\nMessage latency: 15.950 mcs\nMessage throughput: 62693 msg/s\n```\n\n### Unix Domain Socket echo server\n\n* [UdsEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdsEchoServer/Program.cs)\n* [UdsEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdsEchoClient/Program.cs) --clients 1\n\n```\nServer Unix Domain Socket path: C:\\Users\\chronoxor\\AppData\\Local\\Temp\\echo.sock\nWorking clients: 1\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.016 s\nTotal data: 208.657 MiB\nTotal messages: 6836769\nData throughput: 20.850 MiB/s\nMessage latency: 1.465 mcs\nMessage throughput: 682575 msg/s\n```\n\n* [UdsEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdsEchoServer/Program.cs)\n* [UdsEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdsEchoClient/Program.cs) --clients 100\n\n```\nServer Unix Domain Socket path: C:\\Users\\chronoxor\\AppData\\Local\\Temp\\echo.sock\nWorking clients: 100\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 12.253 s\nTotal data: 602.320 MiB\nTotal messages: 19736578\nData throughput: 49.157 MiB/s\nMessage latency: 620 ns\nMessage throughput: 1610666 msg/s\n```\n\n### Simple protocol server\n\n* [ProtoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/ProtoServer/Program.cs)\n* [ProtoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/ProtoClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 4444\nWorking clients: 1\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.015 s\nTotal data: 100.568 MiB\nTotal messages: 3294993\nData throughput: 10.040 MiB/s\nMessage latency: 3.039 mcs\nMessage throughput: 328978 msg/s\n```\n\n* [ProtoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/ProtoServer/Program.cs)\n* [ProtoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/ProtoClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 4444\nWorking clients: 100\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 12.530 s\nTotal data: 207.994 MiB\nTotal messages: 6814785\nData throughput: 16.611 MiB/s\nMessage latency: 1.838 mcs\nMessage throughput: 543858 msg/s\n```\n\n### WebSocket echo server\n\n* [WsEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WsEchoServer/Program.cs)\n* [WsEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WsEchoClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 8080\nWorking clients: 1\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 3.037 s\nTotal data: 105.499 MiB\nTotal messages: 3456618\nData throughput: 34.742 MiB/s\nMessage latency: 878 ns\nMessage throughput: 1137864 msg/s\n```\n\n* [WsEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WsEchoServer/Program.cs)\n* [WsEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WsEchoClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 8080\nWorking clients: 100\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.078 s\nTotal data: 426.803 MiB\nTotal messages: 13984888\nData throughput: 42.353 MiB/s\nMessage latency: 720 ns\nMessage throughput: 1387555 msg/s\n```\n\n### WebSocket secure echo server\n\n* [WssEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WssEchoServer/Program.cs)\n* [WssEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WssEchoClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 8443\nWorking clients: 1\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.030 s\nTotal data: 198.103 MiB\nTotal messages: 6491390\nData throughput: 19.767 MiB/s\nMessage latency: 1.545 mcs\nMessage throughput: 647153 msg/s\n```\n\n* [WssEchoServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WssEchoServer/Program.cs)\n* [WssEchoClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WssEchoClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 8443\nWorking clients: 100\nWorking messages: 1000\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.112 s\nTotal data: 405.286 MiB\nTotal messages: 13280221\nData throughput: 40.078 MiB/s\nMessage latency: 761 ns\nMessage throughput: 1313228 msg/s\n```\n\n## Benchmark: Multicast\n\n![Multicast](https://github.com/chronoxor/NetCoreServer/raw/master/images/multicast.png)\n\nIn this scenario server multicasts messages to all connected clients.\nThe benchmark counts total messages received by all clients for all\nthe working time and measures messages \u0026 data throughput, count\nof errors.\n\n### TCP multicast server\n\n* [TcpMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/TcpMulticastServer/Program.cs)\n* [TcpMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/TcpMulticastClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 1111\nWorking clients: 1\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.022 s\nTotal data: 407.023 MiB\nTotal messages: 13337326\nData throughput: 40.625 MiB/s\nMessage latency: 751 ns\nMessage throughput: 1330734 msg/s\n```\n\n* [TcpMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/TcpMulticastServer/Program.cs)\n* [TcpMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/TcpMulticastClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 1111\nWorking clients: 100\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.112 s\nTotal data: 421.348 MiB\nTotal messages: 13806493\nData throughput: 41.681 MiB/s\nMessage latency: 732 ns\nMessage throughput: 1365280 msg/s\n```\n\n### SSL multicast server\n\n* [SslMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/SslMulticastServer/Program.cs)\n* [SslMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/SslMulticastClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 2222\nWorking clients: 1\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.024 s\nTotal data: 325.225 MiB\nTotal messages: 10656801\nData throughput: 32.453 MiB/s\nMessage latency: 940 ns\nMessage throughput: 1063075 msg/s\n```\n\n* [SslMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/SslMulticastServer/Program.cs)\n* [SslMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/SslMulticastClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 2222\nWorking clients: 100\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.144 s\nTotal data: 343.460 MiB\nTotal messages: 11254173\nData throughput: 33.876 MiB/s\nMessage latency: 901 ns\nMessage throughput: 1109393 msg/s\n```\n\n### UDP multicast server\n\n* [UdpMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdpMulticastServer/Program.cs)\n* [UdpMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdpMulticastClient/Program.cs) --clients 1\n\n```\nServer address: 239.255.0.1\nServer port: 3333\nWorking clients: 1\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.026 s\nTotal data: 13.225 MiB\nTotal messages: 433202\nData throughput: 1.326 MiB/s\nMessage latency: 23.145 mcs\nMessage throughput: 43205 msg/s\n```\n\n* [UdpMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdpMulticastServer/Program.cs)\n* [UdpMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdpMulticastClient/Program.cs) --clients 100\n\n```\nServer address: 239.255.0.1\nServer port: 3333\nWorking clients: 100\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.035 s\nTotal data: 28.684 MiB\nTotal messages: 939408\nData throughput: 2.877 MiB/s\nMessage latency: 10.682 mcs\nMessage throughput: 93606 msg/s\n```\n\n### Unix Domain Socket multicast server\n\n* [UdsMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdsMulticastServer/Program.cs)\n* [UdsMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdsMulticastClient/Program.cs) --clients 1\n\n```\nServer Unix Domain Socket path: C:\\Users\\chronoxor\\AppData\\Local\\Temp\\multicast.sock\nWorking clients: 1\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.015 s\nTotal data: 204.127 MiB\nTotal messages: 6688763\nData throughput: 20.390 MiB/s\nMessage latency: 1.497 mcs\nMessage throughput: 667869 msg/s\n```\n\n* [UdsMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdsMulticastServer/Program.cs)\n* [UdsMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/UdsMulticastClient/Program.cs) --clients 100\n\n```\nServer Unix Domain Socket path: C:\\Users\\chronoxor\\AppData\\Local\\Temp\\multicast.sock\nWorking clients: 100\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.033 s\nTotal data: 124.463 MiB\nTotal messages: 4078051\nData throughput: 12.413 MiB/s\nMessage latency: 2.460 mcs\nMessage throughput: 406451 msg/s\n```\n\n### WebSocket multicast server\n\n* [WsMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WsMulticastServer/Program.cs)\n* [WsMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WsMulticastClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 8080\nWorking clients: 1\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.048 s\nTotal data: 183.108 MiB\nTotal messages: 6000000\nData throughput: 18.228 MiB/s\nMessage latency: 1.674 mcs\nMessage throughput: 597121 msg/s\n```\n\n* [WsMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WsMulticastServer/Program.cs)\n* [WsMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WsMulticastClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 8080\nWorking clients: 100\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.227 s\nTotal data: 125.957 MiB\nTotal messages: 4126627\nData throughput: 12.320 MiB/s\nMessage latency: 2.478 mcs\nMessage throughput: 403466 msg/s\n```\n\n### WebSocket secure multicast server\n\n* [WssMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WssMulticastServer/Program.cs)\n* [WssMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WssMulticastClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 8443\nWorking clients: 1\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.034 s\nTotal data: 184.159 MiB\nTotal messages: 6034421\nData throughput: 18.359 MiB/s\nMessage latency: 1.662 mcs\nMessage throughput: 601338 msg/s\n```\n\n* [WssMulticastServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WssMulticastServer/Program.cs)\n* [WssMulticastClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/WssMulticastClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 8443\nWorking clients: 100\nMessage size: 32\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.171 s\nTotal data: 315.306 MiB\nTotal messages: 10331721\nData throughput: 30.1022 MiB/s\nMessage latency: 984 ns\nMessage throughput: 1015763 msg/s\n```\n\n## Benchmark: Web Server\n\n### HTTP Trace server\n\n* [HttpTraceServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/HttpTraceServer/Program.cs)\n* [HttpTraceClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/HttpTraceClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 8080\nWorking clients: 1\nWorking messages: 1\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.023 s\nTotal data: 10.987 MiB\nTotal messages: 108465\nData throughput: 1.096 MiB/s\nMessage latency: 92.414 mcs\nMessage throughput: 10820 msg/s\n```\n\n* [HttpTraceServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/HttpTraceServer/Program.cs)\n* [HttpTraceClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/HttpTraceClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 8080\nWorking clients: 100\nWorking messages: 1\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 10.085 s\nTotal data: 40.382 MiB\nTotal messages: 401472\nData throughput: 4.003 MiB/s\nMessage latency: 25.120 mcs\nMessage throughput: 39807 msg/s\n```\n\n### HTTPS Trace server\n\n* [HttpsTraceServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/HttpsTraceServer/Program.cs)\n* [HttpsTraceClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/HttpsTraceClient/Program.cs) --clients 1\n\n```\nServer address: 127.0.0.1\nServer port: 8443\nWorking clients: 1\nWorking messages: 1\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 595.214 ms\nTotal data: 627.842 KiB\nTotal messages: 6065\nData throughput: 1.030 MiB/s\nMessage latency: 98.139 mcs\nMessage throughput: 10189 msg/s\n```\n\n* [HttpsTraceServer](https://github.com/chronoxor/NetCoreServer/blob/master/performance/HttpsTraceServer/Program.cs)\n* [HttpsTraceClient](https://github.com/chronoxor/NetCoreServer/blob/master/performance/HttpsTraceClient/Program.cs) --clients 100\n\n```\nServer address: 127.0.0.1\nServer port: 8443\nWorking clients: 100\nWorking messages: 1\nSeconds to benchmarking: 10\n\nErrors: 0\n\nTotal time: 3.548 s\nTotal data: 17.948 MiB\nTotal messages: 179111\nData throughput: 5.052 MiB/s\nMessage latency: 19.813 mcs\nMessage throughput: 50471 msg/s\n```\n\n# OpenSSL certificates\nIn order to create OpenSSL based server and client you should prepare a set of\nSSL certificates.\n\n## Production\nDepending on your project, you may need to purchase a traditional SSL\ncertificate signed by a Certificate Authority. If you, for instance,\nwant some else's web browser to talk to your WebSocket project, you'll\nneed a traditional SSL certificate.\n\n## Development\nThe commands below entered in the order they are listed will generate a\nself-signed certificate for development or testing purposes.\n\n## Certificate Authority\n\n* Create CA private key\n```shell\nopenssl genrsa -passout pass:qwerty -out ca-secret.key 4096\n```\n\n* Remove passphrase\n```shell\nopenssl rsa -passin pass:qwerty -in ca-secret.key -out ca.key\n```\n\n* Create CA self-signed certificate\n```shell\nopenssl req -new -x509 -days 3650 -subj '/C=BY/ST=Belarus/L=Minsk/O=Example root CA/OU=Example CA unit/CN=example.com' -key ca.key -out ca.crt\n```\n\n* Convert CA self-signed certificate to PFX\n```shell\nopenssl pkcs12 -export -passout pass:qwerty -inkey ca.key -in ca.crt -out ca.pfx\n```\n\n* Convert CA self-signed certificate to PEM\n```shell\nopenssl pkcs12 -passin pass:qwerty -passout pass:qwerty -in ca.pfx -out ca.pem\n```\n\n## SSL Server certificate\n\n* Create private key for the server\n```shell\nopenssl genrsa -passout pass:qwerty -out server-secret.key 4096\n```\n\n* Remove passphrase\n```shell\nopenssl rsa -passin pass:qwerty -in server-secret.key -out server.key\n```\n\n* Create CSR for the server\n```shell\nopenssl req -new -subj '/C=BY/ST=Belarus/L=Minsk/O=Example server/OU=Example server unit/CN=server.example.com' -key server.key -out server.csr\n```\n\n* Create certificate for the server\n```shell\nopenssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt\n```\n\n* Convert the server certificate to PFX\n```shell\nopenssl pkcs12 -export -passout pass:qwerty -inkey server.key -in server.crt -out server.pfx\n```\n\n* Convert the server certificate to PEM\n```shell\nopenssl pkcs12 -passin pass:qwerty -passout pass:qwerty -in server.pfx -out server.pem\n```\n\n## SSL Client certificate\n\n* Create private key for the client\n```shell\nopenssl genrsa -passout pass:qwerty -out client-secret.key 4096\n```\n\n* Remove passphrase\n```shell\nopenssl rsa -passin pass:qwerty -in client-secret.key -out client.key\n```\n\n* Create CSR for the client\n```shell\nopenssl req -new -subj '/C=BY/ST=Belarus/L=Minsk/O=Example client/OU=Example client unit/CN=client.example.com' -key client.key -out client.csr\n```\n\n* Create the client certificate\n```shell\nopenssl x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt\n```\n\n* Convert the client certificate to PFX\n```shell\nopenssl pkcs12 -export -passout pass:qwerty -inkey client.key -in client.crt -out client.pfx\n```\n\n* Convert the client certificate to PEM\n```shell\nopenssl pkcs12 -passin pass:qwerty -passout pass:qwerty -in client.pfx -out client.pem\n```\n\n## Diffie-Hellman key exchange\n\n* Create DH parameters\n```shell\nopenssl dhparam -out dh4096.pem 4096\n```\n","funding_links":[],"categories":["NetWork","C#","C\\#","Networking","Audio"],"sub_categories":["GUI - other"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchronoxor%2FNetCoreServer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchronoxor%2FNetCoreServer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchronoxor%2FNetCoreServer/lists"}