Skip to content

Commit c2bfc33

Browse files
release v2.0.0
- [feat] circular buffer for receiving - [feat] yield to utilize thread pool when receiving - [opt] better middleware strategy - [opt] enqueue concurrent (multiple) sends - [misc] perf test
1 parent d00f104 commit c2bfc33

File tree

2 files changed

+174
-49
lines changed

2 files changed

+174
-49
lines changed

Miku.PerformanceTest/README.md

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ This tool addresses [Issue #1](https://github.com/JasonXuDeveloper/Miku/issues/1
77
## Features
88

99
- **Single unified application** with server and client commands
10-
- **Clean CLI argument parsing** using ConsoleAppFramework
1110
- **Multiple test scenarios**: Echo, broadcast, silent (server) / burst, sustained, latency (client)
1211
- **Real-time performance metrics**: Messages/sec, MB/sec, round-trip times
13-
- **Configurable parameters**: Message sizes (100-500 bytes as requested), rates, duration, client counts
12+
- **Configurable parameters**: Message sizes, rates, duration, client counts
1413
- **Interactive server commands**: Change modes, reset metrics, view detailed stats
1514
- **Interactive menu**: Run without any arguments to launch an interactive prompt for Server or Client modes
1615
- **Live controls**: Press `R` to reset the current metrics during a live test
@@ -153,50 +152,6 @@ dotnet run --project Miku.PerformanceTest/Miku.PerformanceTest.csproj client --m
153152
- Critical for interactive applications
154153
- Only meaningful in echo mode or latency testing
155154

156-
## Performance Considerations
157-
158-
As discussed in [Issue #1](https://github.com/JasonXuDeveloper/Miku/issues/1), performance depends on several factors:
159-
160-
### 1. **Bandwidth Limitations**
161-
- Network bandwidth often limits throughput
162-
- Local (LAN) testing shows higher performance than remote testing
163-
164-
### 2. **System Call Overhead**
165-
- High-frequency sending (1000+ msg/s) may be limited by system call overhead
166-
- The Miku library utilizes all CPU cores to mitigate this
167-
168-
### 3. **Test Scenario Impact**
169-
- **Echo mode**: 2x network traffic (send + receive)
170-
- **Broadcast mode**: N×M traffic (N clients × M message size × client count)
171-
- **Silent mode**: Minimal traffic, tests pure receiving performance
172-
173-
### 4. **Message Size Effects**
174-
- Smaller messages (100 bytes): Higher messages/sec, lower MB/sec
175-
- Larger messages (500 bytes): Lower messages/sec, higher MB/sec
176-
177-
## ConsoleAppFramework Benefits
178-
179-
This tool leverages [ConsoleAppFramework](https://github.com/Cysharp/ConsoleAppFramework) for:
180-
181-
- **Zero reflection, zero allocation** CLI parsing
182-
- **Native AOT compatibility** for fast startup
183-
- **Automatic help generation** from XML documentation
184-
- **Type-safe parameter binding**
185-
- **Clean, declarative command structure**
186-
187-
## Building for Production
188-
189-
```bash
190-
# Release build
191-
dotnet build -c Release
192-
193-
# Publish as self-contained executable
194-
dotnet publish -c Release -r win-x64 --self-contained
195-
196-
# Native AOT (requires .NET 8+)
197-
dotnet publish -c Release -r win-x64 -p:PublishAot=true
198-
```
199-
200155
## Contributing
201156

202157
When testing the library performance:

README.md

Lines changed: 173 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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
2732
See [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

Comments
 (0)