Skip to content

C# 传输 API

在 NNRP SDK 术语中,transport provider 是 NNRP framing/runtime 语义下方的 carrier 边界。它 可以使用传输层协议、WebSocket 这样的应用层 carrier,或本地 IPC;这里的 transport 不会重新 定义 OSI transport layer。

NnrpEndpoint

NnrpEndpoint.Parse(string) 只接受用户侧 nnrp://nnrps:// endpoint。不可变值保留 AuthorityPathAndQueryIsSecure,并拒绝 credential、fragment、缺失 authority 和 carrier scheme。

角色 API 接受 NnrpEndpoint;选择 IPC 或 WebSocket 不会迫使应用配置改写 NNRP scheme。

NnrpProviderEndpoint

NnrpProviderEndpoint.Parse(string) 表示显式 carrier-local override,由各 provider 包校验自己 拥有的 locator:

Provider接受的 locator
TCPHost 和 port
QUICHost 和 port
Unix IPCunix://
Windows IPCnpipe://
WebSocketws://wss://

Provider endpoint 用于诊断、conformance 和受控部署。应用代码仍以 NnrpEndpoint 作为逻辑 endpoint,carrier 解析严格遵守以下规则:

  1. 未提供 override 时,TCP 与 QUIC 从应用 authority 派生 host 和 port。
  2. IPC 必须提供匹配的 unix://npipe:// locator。
  3. WebSocket 必须提供匹配的 ws://wss:// locator。
  4. 属于其他 provider 的 locator 或与平台不兼容的 IPC locator,必须在 connect、listen 或 probe 创建 native handle 前拒绝。

无法解析的 client route 必须以 RouteUnresolved candidate 保留在诊断中;Auto/Prefer 可以继续选择 其他可用 route,Force 绝不回退。Server Auto/Prefer 下无法解析 route 属于配置错误,因为逻辑 listener set 必须包含全部允许的已安装 provider。

未知 route key 属于无效配置。为已知但未安装的 transport 提供 route 时,必须产生 LocalUnavailable candidate。多个检查同时失败时按协议 rejection registry 顺序选择原因,因此 RouteUnresolved 优先于 SecurityUnsatisfied

Transport Security

类型冻结值
NnrpTransportClientSecurityServerName、owned TrustedCertificateDer
NnrpTransportServerSecurityowned CertificateDer、owned PrivateKeyPkcs8Der

Client security 只能用于 connect/probe,server security 只能用于 listen。QUIC、启用 TLS 的 TCP 与 wss:// 必须提供对应 security。明文 TCP、IPC 与 ws:// 不满足 nnrps:// 应用 endpoint。

Provider Routes

类型冻结属性
NnrpClientProviderRouteProviderEndpointSecurity
NnrpServerProviderRouteProviderEndpointSecurity

NnrpClientOptions.ProviderRoutesNnrpServerOptions.ProviderRoutes 是按 TransportId 索引的 只读 dictionary。每条 route 只持有一个 carrier 的 locator 与 security。Role-wide ProviderEndpointSecurity 不属于 Preview4 宿主 API。

Provider 契约

csharp
public interface INnrpNativeTransportProvider
{
    NnrpTransportProviderDescriptor Descriptor { get; }

    ValueTask<NnrpTransportConnection> ConnectAsync(
        NnrpTransportConnectOptions options,
        CancellationToken cancellationToken = default);

    ValueTask<NnrpTransportListener> ListenAsync(
        NnrpTransportListenOptions options,
        CancellationToken cancellationToken = default);

    ValueTask<NnrpTransportProbeMetrics> ProbeAsync(
        NnrpTransportProbeOptions options,
        CancellationToken cancellationToken = default);
}

NnrpTransportConnectionNnrpTransportListener 是 opaque、可释放的 ownership value。它们 可以把 carrier ownership 转交给角色 runtime,但不会向应用暴露 FFI handle、pointer 或 native buffer。

Options 类型冻结属性
NnrpTransportConnectOptionsEndpointProviderEndpointSecurityMaxPacketBytesTimeoutMilliseconds
NnrpTransportListenOptionsEndpointProviderEndpointSecurityMaxPacketBytesTimeoutMilliseconds
NnrpTransportProbeOptionsconnect options 加 SampleCountPayloadBytesIncludeWarmup

Provider Metadata

C# 类型冻结属性或值
NnrpTransportProviderKindPureRustNativeDynamicWasm
NnrpTransportProviderCostModelId: ushortUnits: ulong
NnrpTransportProviderLimitsMaxFrameBytes: ulong
NnrpTransportProviderLimitationRequiresUdpRequiresTcpLocalHostOnlyNativeHostOnlyBrowserHostOnlyUnixDomainSocketWindowsNamedPipe
NnrpTransportProviderMetadataId: stringCost: NnrpTransportProviderCostPreferenceRank: ushortLimits: NnrpTransportProviderLimitsLimitations: IReadOnlyList<NnrpTransportProviderLimitation>
NnrpTransportProviderDescriptorName: stringVersion: stringTransportId: TransportIdKind: NnrpTransportProviderKindAvailable: boolLibraryPath: string?Metadata: NnrpTransportProviderMetadataDiagnostic: string?
NnrpTransportCandidateReadinessTransportId: TransportIdProviderId: stringRouteResolved: boolSecuritySatisfied: boolDiagnostic: string?
NnrpTransportProbeStateNotRunSucceededFailedMissing
NnrpTransportProbeMetricsSampleCount: uintSuccessCount: uintMedianThroughputBytesPerSecond: ulongMedianRttMicroseconds: ulong
NnrpTransportProbeObservationTransportId: TransportIdProviderId: stringState: NnrpTransportProbeStateMetrics: NnrpTransportProbeMetrics?Diagnostic: string?;state 只能是 SucceededFailed
NnrpTransportRejectionReasonPolicyDisallowedLocalUnavailablePeerUnsupportedLimitExceededRouteUnresolvedSecurityUnsatisfiedProbeMissingProbeFailed
NnrpTransportCandidateTransportId: TransportIdProvider: NnrpTransportProviderMetadataLocalAvailable: boolPeerSupported: boolWithinLimits: boolProbeState: NnrpTransportProbeStateProbe: NnrpTransportProbeMetrics?SelectionRank: uint?RejectionReason: NnrpTransportRejectionReason?Diagnostic: string?
NnrpTransportSelectionSelectedProvider: NnrpTransportProviderDescriptor、有序 Candidates: IReadOnlyList<NnrpTransportCandidate>Policy: TransportPolicyDiagnostic: string?
NnrpTransportSelectionExceptionCode: NnrpTransportSelectionErrorCodePolicy: TransportPolicy?TransportId: TransportId?Candidates: IReadOnlyList<NnrpTransportCandidate>Diagnostic: string;强制策略失败会标明 transport,InvalidEvidence 在 selection 前发生

NnrpTransportProviderDescriptor.Name 是 provider 自有的 package 名或展示名。Registry lookup、readiness、 selection、route lookup 与 reporting 使用 TransportId,不得从 Name 推导 carrier 身份。

NnrpTransportSelectionOptions 冻结 registry selection 的输入:

属性类型必填说明
PeerSupportedTransportsIReadOnlyCollection<TransportId>Peer 声明的 carrier 交集。
PolicyTransportPolicy默认值为 Auto
RequestedMaxFrameBytesulong?对照 Provider.Limits.MaxFrameBytes 校验的 workload limit。
CandidateReadinessIReadOnlyCollection<NnrpTransportCandidateReadiness>每个已注册 provider 的 route/security evidence。
ProbeObservationsIReadOnlyCollection<NnrpTransportProbeObservation>?按 transport 与 provider identity 匹配的成功/失败 evidence。

PeerSupportedTransports 按集合解释,重复项和枚举顺序不影响选择;RequestedMaxFrameBytes = 0 是合法值, 并且与 null 含义不同。

Metadata 必须与 Rust artifact manifest 一致。C# 使用 Transport Strategy and Probing 冻结的 comparator,不创造 自己的加权分数。

NnrpNativeTransportRegistry

方法语义
Register(INnrpNativeTransportProvider)注册一个 provider,拒绝重复 provider 或 transport ID。
Snapshot()返回不可变、稳定顺序的 provider snapshot。
Resolve(NnrpTransportSelectionOptions)执行过滤和选择;没有 provider 可选时抛出携带完整 candidates 的 NnrpTransportSelectionException

安装的一方包会注册 NnrpNativeTcpTransportProviderNnrpNativeQuicTransportProviderNnrpNativeIpcTransportProviderNnrpNativeWebSocketTransportProvider 到内部默认 registry。 公开角色 options 不接受 provider 实例或 native handle;ProviderRoutes 提供 provider endpoint 意图, TransportPolicy 则约束对已安装包的选择。

只有一个有效 provider 时直接选择;多个有效 provider 才进入冻结的 probe/comparison 路径。 被拒绝的 candidate 仍保留在 NnrpTransportSelection 中。

注册必须拒绝重复 transport ID 与重复 provider metadata ID,且不得替换先注册的 provider。Readiness 与 probe observation 按 (TransportId, ProviderId) 匹配;重复、无法匹配或不完整的 readiness 属于无效输入。 没有匹配 probe observation 表示 Missing,state 为 Failed 的 observation 必须保持为独立失败。

一方包

具体 Provider持有的产物
Nnrp.Transport.TcpNnrpNativeTcpTransportProvider仅 TCP
Nnrp.Transport.QuicNnrpNativeQuicTransportProvider仅 QUIC
Nnrp.Transport.IpcNnrpNativeIpcTransportProvider仅 IPC
Nnrp.Transport.WebSocketNnrpNativeWebSocketTransportProvider仅 WebSocket

每个包持有自己的具体 provider descriptor 与 transport-scoped Rust artifact。具体 provider 暴露 connect、 listen 与 probe;Nnrp.NativeBridge 统一持有粗粒度 FFI 调用与 native handle 生命周期机制。client 与 server 包不携带 transport artifact。

诊断 Framed Transport

INnrpMessageSenderINnrpMessageReceiverINnrpMessageTransportNnrpTcpMessageTransport 只属于底层 packet 诊断/自定义 carrier 契约。它们不参与生产 provider 选择,也不是 native artifact 缺失时的 fallback。

NNRP Documentation