@@ -5,14 +5,19 @@ High performance TCP server/client library
55## Features
66- Asynchronous I/O based TCP server/client
77- Accepting Middlewares to handle incoming and outgoing data
8+ - Zero-allocation ring buffers for high-throughput streaming
9+ - Event-driven, non-blocking operations with back-pressure support
10+ - Built-in performance metrics: messages/sec, MB/sec, latency
11+ - Cross-platform support: .NET Standard 2.1, .NET 6.0, .NET 8.0
12+ - Extensible pipeline for framing, compression, encryption
813
914## Performance Testing
1015
11- The project includes a unified performance test tool built with [ ConsoleAppFramework ] ( https://github.com/Cysharp/ConsoleAppFramework ) to measure "messages per second" and throughput for different scenarios:
16+ The project includes a unified performance test tool measures "messages per second" and throughput for different scenarios:
1217
1318- ** Single unified application** with server and client commands
1419- ** Multiple test scenarios** : Echo, broadcast, silent (server) / burst, sustained, latency (client)
15- - ** Configurable parameters** : Message sizes (100-500 bytes) , rates, duration, client counts
20+ - ** Configurable parameters** : Message sizes, rates, duration, client counts
1621- ** Real-time performance metrics** : Messages/sec, MB/sec, round-trip times
1722
1823### Quick Start
@@ -27,4 +32,169 @@ dotnet run --project Miku.PerformanceTest/Miku.PerformanceTest.csproj client --s
2732See [ Miku.PerformanceTest/README.md] ( Miku.PerformanceTest/README.md ) for detailed usage instructions and performance testing scenarios.
2833
2934## Documentation
30- TODO
35+
36+ ### NetClient
37+
38+ NetClient allows you to connect to a TCP server, send/receive raw byte data, and track connection lifecycle.
39+
40+ #### Constructors
41+ - ` NetClient() ` : Create a new client instance.
42+
43+ #### Connection
44+ - ` void Connect(string ip, int port, int bufferSize = 1024) ` : Connect to a server at the given IP and port. Optionally specify receive buffer size.
45+ - ` bool IsConnected { get; } ` : Indicates if the client is connected.
46+ - ` string Ip { get; } ` : Remote endpoint IP.
47+
48+ #### Data Transfer
49+ - ` void Send(ReadOnlyMemory<byte> data) ` : Sends raw data to the server.
50+ - ` event Action<ReadOnlyMemory<byte>> OnDataReceived ` : Raised when data is received from the server.
51+
52+ #### Events & Lifecycle
53+ - ` event Action OnConnected ` : Raised upon successful connection.
54+ - ` event Action<string> OnDisconnected ` : Raised when the client disconnects, with reason.
55+ - ` event Action<Exception> OnError ` : Raised on errors.
56+ - ` void Stop(string reason = "Connection closed by client", bool includeCallStack = false) ` : Gracefully stops the client.
57+
58+ #### Properties
59+ - ` int Id { get; } ` : Unique identifier for this client instance.
60+ - ` int BufferSize { get; } ` : Configured receive buffer capacity.
61+ - ` NetClientStats Stats { get; } ` : Performance statistics (messages sent/received, bytes sent/received, drops).
62+ - ` bool HasPendingSends { get; } ` : Whether there are pending outgoing messages.
63+ - ` int PendingSendCount { get; } ` : Number of messages queued for sending.
64+
65+ #### Utilities
66+ - ` void ResetStats() ` : Reset all performance counters to zero.
67+ - ` string GetDiagnosticInfo() ` : Retrieve detailed diagnostic information (buffer usage, stats, connection state).
68+
69+ ### NetServer
70+
71+ NetServer listens for incoming TCP connections and dispatches data to subscribed clients.
72+
73+ #### Configuration
74+ - ` int BufferSize { get; set; } ` : Size of send/receive buffer (default: 64 KiB).
75+
76+ #### Lifecycle
77+ - ` void Start(string ip, int port, int backLog = 1000) ` : Begin listening on the specified IP and port.
78+ - ` void Stop() ` : Stop listening and disconnect all clients.
79+ - ` bool IsListening { get; } ` : Indicates if server is active.
80+ - ` int ClientCount { get; } ` : Current number of connected clients.
81+
82+ #### Events
83+ - ` event Action<NetClient> OnClientConnected ` : Triggered when a client connects.
84+ - ` event Action<NetClient, string> OnClientDisconnected ` : Triggered when a client disconnects, with reason.
85+ - ` event Action<NetClient, ReadOnlyMemory<byte>> OnClientDataReceived ` : Triggered when a client sends data.
86+ - ` event Action<Exception> OnError ` : Triggered on server errors.
87+
88+ ### Middleware
89+
90+ Implement ` INetMiddleware ` to process data before sending or after receiving:
91+
92+ ``` csharp
93+ public interface INetMiddleware
94+ {
95+ void ProcessSend (ReadOnlyMemory <byte > src , ArrayBufferWriter <byte > dst );
96+ (bool halt , int consumedFromOrigin ) ProcessReceive (ReadOnlyMemory <byte > src , ArrayBufferWriter <byte > dst );
97+ }
98+ ```
99+
100+ - ` ProcessSend ` : Transform or wrap outgoing data. Write to ` dst ` .
101+ - ` ProcessReceive ` : Transform or unwrap incoming data. Return ` (halt: true, consumed) ` to buffer until ready. You should only ` halt ` when fails to process incoming data. For ` consumed ` , you should return a number of consumed bytes ** related** to the original buffer (e.g. what you originally received from the socket).
102+
103+ ** Built-in middleware examples:**
104+ - ` PacketFrameMiddleware ` : Prepends a 4-byte length header for framing.
105+ - ` Lz4CompressionMiddleware ` : Compresses/decompresses data with LZ4.
106+
107+ ### Examples
108+
109+ #### Echo Server and Client
110+
111+ ``` csharp
112+ // Server
113+ var server = new NetServer ();
114+ server .OnClientConnected += c => Console .WriteLine ($" Client connected: {c .Ip }" );
115+ server .OnClientDataReceived += (c , data ) => c .Send (data .ToArray ());
116+ server .OnError += e => Console .WriteLine (e );
117+ server .Start (" 0.0.0.0" , 54323 );
118+
119+ // Client
120+ var client = new NetClient ();
121+ client .OnDataReceived += data =>
122+ {
123+ Console .WriteLine ($" Echoed: {string .Join (',' , data .ToArray ())}" );
124+ client .Stop ();
125+ server .Stop ();
126+ };
127+ client .Connect (" 127.0.0.1" , 54323 );
128+ client .Send (new byte []{1 ,2 ,3 ,4 ,5 });
129+ ```
130+
131+ #### Framing Middleware
132+
133+ ``` csharp
134+ // Server
135+ var server = new NetServer ();
136+ server .OnClientConnected += c => c .AddMiddleware (new PacketFrameMiddleware ());
137+ server .OnClientDataReceived += (c , data ) => c .Send (data .ToArray ());
138+ server .Start (" 0.0.0.0" , 54324 );
139+
140+ // Client
141+ var client = new NetClient ();
142+ client .AddMiddleware (new PacketFrameMiddleware ());
143+ client .OnDataReceived += data => Console .WriteLine ($" Received: {string .Join (',' , data .ToArray ())}" );
144+ client .Connect (" 127.0.0.1" , 54324 );
145+ client .Send (new byte []{1 ,2 ,3 ,4 ,5 });
146+ ```
147+
148+ #### Compression + Framing Middleware
149+
150+ ``` csharp
151+ var server = new NetServer ();
152+ server .OnClientConnected += c =>
153+ {
154+ c .AddMiddleware (new Lz4CompressionMiddleware ());
155+ c .AddMiddleware (new PacketFrameMiddleware ());
156+ };
157+ server .OnClientDataReceived += (c , data ) => c .Send (data .ToArray ());
158+ server .Start (" 0.0.0.0" , 54324 );
159+
160+ var client = new NetClient ();
161+ client .AddMiddleware (new Lz4CompressionMiddleware ());
162+ client .AddMiddleware (new PacketFrameMiddleware ());
163+ client .OnDataReceived += data => Console .WriteLine ($" Received: {string .Join (',' , data .ToArray ())}" );
164+ client .Connect (" 127.0.0.1" , 54324 );
165+ client .Send (new byte []{1 ,2 ,3 ,4 ,5 });
166+ ```
167+
168+ #### Ping-Pong Protocol
169+
170+ ``` csharp
171+ // Server: deserialize Ping, reply with Pong
172+ server .OnClientConnected += c =>
173+ {
174+ c .AddMiddleware (new Lz4CompressionMiddleware ());
175+ c .AddMiddleware (new PacketFrameMiddleware ());
176+ };
177+ server .OnClientDataReceived += (c , data ) =>
178+ {
179+ Deserializer .Deserialize (data .Span , out IProtocol msg );
180+ if (msg is Ping ping )
181+ {
182+ // validate ping
183+ c .Send (pong .Serialize ());
184+ }
185+ };
186+
187+ // Client
188+ var client = new NetClient ();
189+ client .AddMiddleware (new Lz4CompressionMiddleware ());
190+ client .AddMiddleware (new PacketFrameMiddleware ());
191+ client .OnDataReceived += data =>
192+ {
193+ Deserializer .Deserialize (data .Span , out IProtocol msg );
194+ if (msg is Pong ) Console .WriteLine (" Received Pong!" );
195+ client .Stop ();
196+ server .Stop ();
197+ };
198+ client .Connect (" 127.0.0.1" , 54324 );
199+ client .Send (ping .Serialize ());
200+ ```
0 commit comments