565 lines
11 KiB
Markdown
565 lines
11 KiB
Markdown
# EonaCat.Network
|
|
|
|
[](https://www.nuget.org/packages/EonaCat.Network/)
|
|
[](https://www.nuget.org/packages/EonaCat.Network/)
|
|
[](LICENSE)
|
|
|
|
**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).
|