This commit is contained in:
2026-09-21 16:25:06 +02:00
parent b60c6ba953
commit a12974d870
7 changed files with 601 additions and 5 deletions
@@ -23,6 +23,11 @@ namespace EonaCat.Network
public event Action<RemoteInfo> OnDisconnect;
public event Action<Exception, string> OnError;
public async Task ConnectAsync(IPAddress ipAddress, int port, bool useSsl = false, SslOptions sslOptions = null)
{
await CreateSocketTcpClientAsync(ipAddress, port, useSsl, sslOptions);
}
public async Task ConnectAsync(string ipAddress, int port, bool useSsl = false, SslOptions sslOptions = null)
{
if (!IPAddress.TryParse(ipAddress, out var ip))
@@ -32,8 +32,12 @@ namespace EonaCat.Network
public SocketTcpServer(string ipAddress, int port, X509Certificate2 certificate = null, SslOptions sslOptions = null)
{
var address = IPAddress.Parse(ipAddress);
_listener = new TcpListener(address, port);
if (!IPAddress.TryParse(ipAddress, out var ip))
{
throw new ArgumentException("Invalid ipAddress given");
}
_listener = new TcpListener(ip, port);
_certificate = certificate;
_sslOptions = sslOptions;
}
@@ -21,6 +21,22 @@ public class SocketUdpClient
CreateUdpClient(ipAddress, port, cancellationToken);
}
/// <summary>
/// Create UDP client
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="cancellationToken"></param>
public SocketUdpClient(string ipAddress, int port, CancellationToken cancellationToken = default)
{
if (!IPAddress.TryParse(ipAddress, out var ip))
{
throw new ArgumentException("Invalid ipAddress given");
}
CreateUdpClient(ip, port, cancellationToken);
}
public bool IsMulticastGroupEnabled { get; set; }
public bool IsIp6 { get; private set; }
@@ -17,6 +17,19 @@ namespace EonaCat.Network
public event Action<RemoteInfo> OnSend;
public event Action<Exception, string> OnError;
public SocketUdpServer(string ipAddress, int port)
{
if (!IPAddress.TryParse(ipAddress, out var ip))
{
throw new ArgumentException("Invalid ipAddress given");
}
_udpClient = new UdpClient(ip.AddressFamily);
IsIPv6 = ip.AddressFamily == AddressFamily.InterNetworkV6;
_udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_udpClient.Client.Bind(new IPEndPoint(ip, port));
}
public SocketUdpServer(IPAddress ipAddress, int port)
{
_udpClient = new UdpClient(ipAddress.AddressFamily);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 1019 KiB

+561 -3
View File
@@ -1,6 +1,564 @@
# EonaCat Network
# EonaCat.Network
------------
[![NuGet](https://img.shields.io/nuget/v/EonaCat.Network.svg)](https://www.nuget.org/packages/EonaCat.Network/)
[![NuGet Downloads](https://img.shields.io/nuget/dt/EonaCat.Network.svg)](https://www.nuget.org/packages/EonaCat.Network/)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
EonaCat Network Library
**EonaCat.Network** is a .NET networking library that provides a common set of APIs for building networked applications and services.
The library includes support for:
- TCP client and server communication
- UDP client and server communication
- WebSockets
- An embedded HTTP/HTTPS web server
- HTTP routing, including static and parameterized routes
- QUIC client/server and stream primitives
- IPv4 and IPv6 networking
- TCP SSL/TLS support
- WebSocket extensions, fragmentation and compression support
- Network-related helper and utility classes
## Installation
Install the NuGet package:
```bash
dotnet add package EonaCat.Network
```
NuGet:
https://www.nuget.org/packages/EonaCat.Network/
## Target Frameworks
The library currently targets:
- .NET Framework 4.8 (`net48`)
- .NET Standard 2.1
- .NET 6
- .NET 7
- .NET 8
## Quick Start
### TCP server
```csharp
using EonaCat.Network;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
var server = new SocketTcpServer(IPAddress.Any, 5000);
server.OnConnect += remote =>
{
Console.WriteLine("Client connected");
};
server.OnReceive += (remote, message) =>
{
Console.WriteLine($"Received: {message}");
};
server.OnDisconnect += remote =>
{
Console.WriteLine("Client disconnected");
};
server.OnError += (exception, message) =>
{
Console.WriteLine(message);
};
await server.StartAsync(CancellationToken.None);
```
### TCP client
```csharp
using EonaCat.Network;
var client = new SocketTcpClient();
client.OnConnect += remote =>
{
Console.WriteLine("Connected");
};
client.OnReceive += remote =>
{
Console.WriteLine($"Received {remote.Data?.Length ?? 0} bytes");
};
client.OnDisconnect += remote =>
{
Console.WriteLine("Disconnected");
};
client.OnError += (exception, message) =>
{
Console.WriteLine(message);
};
await client.ConnectAsync("127.0.0.1", 5000);
await client.SendAsync(
System.Text.Encoding.UTF8.GetBytes("Hello from EonaCat.Network!"));
```
### UDP server
```csharp
using EonaCat.Network;
using System.Net;
var server = new SocketUdpServer(IPAddress.Any, 5001);
server.OnReceive += remote =>
{
Console.WriteLine($"Received {remote.Data?.Length ?? 0} bytes");
};
server.OnSend += remote =>
{
Console.WriteLine("UDP packet sent");
};
server.OnError += (exception, message) =>
{
Console.WriteLine(message);
};
await server.StartAsync();
```
Send a packet:
```csharp
await server.SendToAsync(
new IPEndPoint(IPAddress.Loopback, 5002),
System.Text.Encoding.UTF8.GetBytes("Hello UDP"));
```
### UDP client
```csharp
using EonaCat.Network;
using System.Net;
var client = new SocketUdpClient(IPAddress.Loopback, 5001);
client.OnReceive += data =>
{
Console.WriteLine($"Received {data.Length} bytes");
};
client.OnError += (exception, message) =>
{
Console.WriteLine(message);
};
await client.SendTo(
new IPEndPoint(IPAddress.Loopback, 5001),
System.Text.Encoding.UTF8.GetBytes("Hello UDP"));
```
## Embedded Web Server
The library includes an HTTP/HTTPS web server exposed through `WebServer` (`EonaCat.Network.WebServer`).
### Start a web server
```csharp
using EonaCat.Network;
var server = new WebServer("localhost", 8080);
await server.StartAsync();
```
For synchronous startup:
```csharp
server.Start();
```
Stop it with:
```csharp
server.Stop();
```
Or dispose it:
```csharp
server.Dispose();
```
### Web server settings
You can configure the server through `EonaCatWebserverSettings`:
```csharp
using EonaCat.Network;
var settings = new EonaCatWebserverSettings("localhost", 8080);
settings.IO.MaxRequests = 1024;
settings.IO.StreamBufferSize = 65536;
settings.Debug.Requests = true;
settings.Debug.Responses = true;
settings.Debug.Routing = true;
var server = new WebServer(settings);
await server.StartAsync();
```
The settings API includes:
- Listening prefixes
- I/O buffer size
- Maximum concurrent requests
- SSL settings
- Default response headers
- Access-control configuration
- Debug logging options
> **Security note:** review the SSL and access-control configuration before exposing a server to an untrusted network. The current settings class allows invalid certificates by default, so production deployments should explicitly configure certificate validation behavior appropriate to the application.
### Web server events
The server exposes events for common lifecycle and HTTP operations through `server.Events`, including:
- `ConnectionReceived`
- `RequestReceived`
- `RequestDenied`
- `RequestorDisconnected`
- `ResponseSent`
- `ExceptionEncountered`
- `ServerStarted`
- `ServerStopped`
- `ServerDisposing`
Example:
```csharp
server.Events.ServerStarted += (_, _) =>
{
Console.WriteLine("Web server started");
};
server.Events.RequestReceived += (_, args) =>
{
Console.WriteLine("HTTP request received");
};
```
## HTTP Routing
EonaCat.Network provides several route types.
### Static routes
`StaticRouteManager` matches an HTTP method and exact path.
```csharp
var routes = new StaticRouteManager();
routes.Add(
HttpMethod.GET,
"/hello",
async context =>
{
// Build and send the response here.
await Task.CompletedTask;
});
```
Static routes normalize paths to begin and end with `/` and use case-insensitive matching.
Useful operations include:
```csharp
routes.Add(...);
routes.Get(HttpMethod.GET, "/hello");
routes.Exists(HttpMethod.GET, "/hello");
routes.Remove(HttpMethod.GET, "/hello");
```
### Parameter routes
`ParameterRouteManager` supports URL parameters such as:
```text
GET /api/{version}/users
```
Example:
```csharp
var routes = new ParameterRouteManager();
routes.Add(
HttpMethod.GET,
"/api/{version}/users",
async context =>
{
await Task.CompletedTask;
});
```
The matching operation returns the extracted values:
```csharp
Dictionary<string, string> values;
ParameterRoute route;
var handler = routes.Match(
HttpMethod.GET,
"/api/v1/users",
out values,
out route);
```
For the example above, `values` can contain:
```text
version = v1
```
## WebSockets
The library contains asynchronous WebSocket client and server implementations under the `EonaCat.WebSockets` namespace.
Supported functionality includes:
- Text messages
- Binary messages
- Streaming binary data
- Sessions
- Broadcasting
- Fragmentation
- Close handling
- Sub-protocol support
- WebSocket extensions
- Per-message compression support
### WebSocket client
```csharp
using EonaCat.WebSockets;
var client = new AsyncWebSocketClient(
new Uri("ws://localhost:8080/"));
await client.ConnectAsync();
await client.SendTextAsync("Hello WebSocket!");
```
Binary data:
```csharp
await client.SendBinaryAsync(
System.Text.Encoding.UTF8.GetBytes("Binary message"));
```
Close the connection:
```csharp
await client.CloseAsync();
```
### WebSocket server
The server uses `AsyncWebSocketServerModule` implementations to handle sessions and messages.
A module can override handlers such as:
```csharp
public override async Task OnSessionStarted(
AsyncWebSocketSession session)
{
await session.SendTextAsync("Welcome!");
}
public override async Task OnSessionTextReceived(
AsyncWebSocketSession session,
string text)
{
await session.SendTextAsync($"Echo: {text}");
}
public override async Task OnSessionBinaryReceived(
AsyncWebSocketSession session,
byte[] data,
int offset,
int count)
{
await Task.CompletedTask;
}
public override async Task OnSessionClosed(
AsyncWebSocketSession session)
{
await base.OnSessionClosed(session);
}
```
Server instances can send to individual sessions or broadcast to all connected sessions:
```csharp
await server.SendTextToAsync(sessionKey, "Hello");
await server.BroadcastTextAsync("Message for everyone");
```
Binary equivalents are also available.
## QUIC
EonaCat.Network contains a QUIC implementation with connection and stream abstractions.
The main public types include:
- `QuicClient`
- `QuicServer`
- `QuicConnection`
- `QuicStream`
- `StreamType`
- QUIC packet and frame infrastructure
- QUIC settings and protocol helpers
### QUIC client
```csharp
using EonaCat.Quic;
var client = new QuicClient();
var connection = client.Connect("127.0.0.1", 11000);
var stream = connection.CreateStream(
StreamType.ClientBidirectional);
stream.Send(
System.Text.Encoding.UTF8.GetBytes("Hello QUIC"));
```
### QUIC server
```csharp
using EonaCat.Quic;
var server = new QuicServer("0.0.0.0", 11000);
server.OnClientConnected += connection =>
{
Console.WriteLine("QUIC client connected");
};
server.Start();
```
> **Important:** the QUIC implementation is part of this library's own protocol stack. Validate the protocol behavior, interoperability and security characteristics against your application's requirements before using it for production Internet-facing workloads.
## `NetworkHelper`
For simple QUIC scenarios, `NetworkHelper` provides convenience methods:
```csharp
using EonaCat.Network;
NetworkHelper.QuicStartServer("0.0.0.0", 11000);
var stream = NetworkHelper.QuicStartClient(
"127.0.0.1",
11000);
NetworkHelper.QuicStopServer();
```
It also exposes events for:
- `OnQuicClientConnected`
- `OnQuicStreamOpened`
- `OnQuicStreamDataReceived`
The default global encoding is UTF-8:
```csharp
NetworkHelper.GlobalEncoding = System.Text.Encoding.UTF8;
```
## IPv4 and IPv6
The socket implementations support IPv4 and IPv6 where supported by the underlying .NET socket APIs.
The library also exposes:
```csharp
public enum IPType : byte
{
IPv4,
IPv6
}
```
TCP and UDP implementations expose IPv6-related information through their connection/remote information objects.
## TCP SSL/TLS
TCP clients and servers can use SSL/TLS.
Client example:
```csharp
var client = new SocketTcpClient();
await client.ConnectAsync(
"127.0.0.1",
5000,
useSsl: true,
sslOptions: new SslOptions());
```
The TCP server accepts a certificate and SSL options:
```csharp
var server = new SocketTcpServer(
"0.0.0.0",
5000,
certificate,
sslOptions);
```
Always use certificates and TLS settings appropriate for the environment in which the application is deployed.
## Dependencies
The package uses several EonaCat and .NET dependencies, including:
- EonaCat.Controls
- EonaCat.Json
- EonaCat.LogStack
- EonaCat.LogSystem
- EonaCat.Matchers
- EonaCat.Versioning
- System.Net.WebSockets
- System.Text.Encodings.Web
These are restored automatically when installing the NuGet package.
## License
EonaCat.Network is released under the **Apache License 2.0**.
See [LICENSE](LICENSE) for the complete license text.
Copyright © EonaCat (Jeroen Saey).
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 1019 KiB