TCP Listener
On this page
Namespace: Nalix.Network.Listeners.Tcp
Assembly: Nalix.Network
TcpListenerBase (public abstract partial class TcpListenerBase : IListener) is the base TCP server listener in Nalix.Network (and the base class of WebSocketListenerBase). It manages socket binding, multi-worker SocketAsyncEventArgs accept loops, optional PROXY Protocol v1/v2 real-IP extraction, ConnectionGuard admission control, a bounded accept-processing channel, and TimingWheel registration.
Source Mapping
src/Nalix.Abstractions/Networking/IListener.cssrc/Nalix.Network/Listeners/TcpListener/TcpListener.Core.cssrc/Nalix.Network/Listeners/TcpListener/TcpListener.PublicMethods.cssrc/Nalix.Network/Listeners/TcpListener/TcpListener.Handle.cssrc/Nalix.Network/Listeners/TcpListener/TcpListener.ProcessChannel.cssrc/Nalix.Network/Listeners/TcpListener/TcpListener.ProxyProtocol.cssrc/Nalix.Network/Listeners/TcpListener/TcpListener.SocketConfig.cssrc/Nalix.Network/Listeners/TcpListener/TcpListener.Synchronization.cssrc/Nalix.Network/Listeners/TcpListener/TcpListener.Metrics.cssrc/Nalix.Network/Options/NetworkSocketOptions.cssrc/Nalix.Network/Options/ProxyProtocolOptions.cs
Accept & Initialization Pipeline
flowchart TD
Sock["Listening Socket (Port)"] --> Acc["SAEA Accept Worker (MaxParallel)"]
Acc --> Proxy{"ProxyProtocolOptions.Enabled?"}
Proxy -->|No| Guard["ConnectionGuard.TryAccept(remoteEndPoint)"]
Proxy -->|Yes| ProxyGate["RequireTrustedProxy Check + Async PROXY v1/v2 Header Read"]
ProxyGate -->|Valid Header| GuardReal["ConnectionGuard.TryAccept(realEndPoint)"]
ProxyGate -->|Timeout / Invalid| Close["Close Socket"]
Guard -->|Rejected| Close
Guard -->|Accepted| Enq["Bounded ProcessChannel.Writer.TryWrite"]
GuardReal -->|Accepted| Enq
GuardReal -->|Rejected| Close
Enq -->|Channel Full| Release["Limiter.Release + Close Socket"]
Enq -->|Queued| Drain["ProcessChannel Consumer Worker"]
Drain --> Init["InitializeAcceptedSocket (Connection + FramePipeline + TimingWheel)"]
Init --> Proto["IProtocol.OnAccept(connection, ct)"]Constructors & Public API
namespace Nalix.Network.Listeners.Tcp;
public abstract partial class TcpListenerBase : IListener
{
protected TcpListenerBase(ushort port, IProtocol protocol, IConnectionHub hub, IConnectionGuard guard);
protected TcpListenerBase(IProtocol protocol, IConnectionHub hub, IConnectionGuard guard);
public int ProcessChannelCount { get; }
public Metrics Metrics { get; }
protected internal IConnectionGuard Limiter { get; }
public virtual void Activate(CancellationToken cancellationToken = default);
public virtual void Deactivate(CancellationToken cancellationToken = default);
public virtual string GenerateReport();
public virtual void WriteReportData(Utf8JsonWriter writer);
public void Dispose();
protected virtual void Dispose(bool disposing);
}
Key Subsystems
1. Socket Binding & Tuning (TcpListener.SocketConfig.cs)
- Dual-Stack IPv6 / IPv4 Fallback: When
NetworkSocketOptions.EnableDualStackistrue(default),TcpListenerBasebinds anInterNetworkV6socket withDualMode = _config.DualMode(true), falling back toInterNetwork(IPv4) if the OS does not support IPv6 dual-stack. - Socket Options: Configures
ReuseAddress,ReusePort,TcpFastOpen,Backlog(512),NoDelay(true),SendBufferSize/ReceiveBufferSize(BufferSize = 65536), and cross-platform TCP Keep-Alive probes (3stime,1sinterval,3retries).
2. PROXY Protocol v1/v2 (TcpListener.ProxyProtocol.cs)
When ProxyProtocolOptions.Enabled is true:
- If
ProxyProtocolOptions.RequireTrustedProxyistrue, only physical peers matchingTrustedProxyOptionsare permitted to send a PROXY header. - Bounds concurrent in-flight PROXY header reads to
ProxyProtocolOptions.MaxPendingProxyConnections(1024) with a timeout ofHeaderTimeoutMs(2000ms). - Parses PROXY v1 or v2 headers via
ProxyProtocolParser, extracts the real clientEndPoint, passes it toConnectionGuard.TryAccept, and injects any leftover bytes into theConnectionviaInjectPreReadBytes.
3. Bounded Accept Process Channel (TcpListener.ProcessChannel.cs)
- Accepted connections are written into a
Channel.CreateBounded<AcceptConnectionResult>sized toNetworkSocketOptions.ProcessChannelCapacity(256). - If the consumer thread is saturated and
TryWritereturnsfalse, the listener calls_limiter.Release(remoteEndPoint)and closes the socket immediately. - During
Deactivate, the listener waits up toNetworkSocketOptions.ProcessChannelDrainTimeout(5000ms) for queued accepts to drain gracefully. - Optional CPU pinning for the dispatch consumer thread is supported via
NetworkSocketOptions.DispatchProcessorAffinity(default-1).