C# 传输 API
在 NNRP SDK 术语中,transport provider 是 NNRP framing/runtime 语义下方的 carrier 边界。它 可以使用传输层协议、WebSocket 这样的应用层 carrier,或本地 IPC;这里的 transport 不会重新 定义 OSI transport layer。
NnrpEndpoint
NnrpEndpoint.Parse(string) 只接受用户侧 nnrp:// 和 nnrps:// endpoint。不可变值保留 Authority、PathAndQuery 和 IsSecure,并拒绝 credential、fragment、缺失 authority 和 carrier scheme。
角色 API 接受 NnrpEndpoint;选择 IPC 或 WebSocket 不会迫使应用配置改写 NNRP scheme。
NnrpProviderEndpoint
NnrpProviderEndpoint.Parse(string) 表示显式 carrier-local override,由各 provider 包校验自己 拥有的 locator:
| Provider | 接受的 locator |
|---|---|
| TCP | Host 和 port |
| QUIC | Host 和 port |
| Unix IPC | unix:// |
| Windows IPC | npipe:// |
| WebSocket | ws:// 或 wss:// |
Provider endpoint 用于诊断、conformance 和受控部署。应用代码仍以 NnrpEndpoint 作为逻辑 endpoint,carrier 解析严格遵守以下规则:
- 未提供 override 时,TCP 与 QUIC 从应用 authority 派生 host 和 port。
- IPC 必须提供匹配的
unix://或npipe://locator。 - WebSocket 必须提供匹配的
ws://或wss://locator。 - 属于其他 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
| 类型 | 冻结值 |
|---|---|
NnrpTransportClientSecurity | ServerName、owned TrustedCertificateDer |
NnrpTransportServerSecurity | owned CertificateDer、owned PrivateKeyPkcs8Der |
Client security 只能用于 connect/probe,server security 只能用于 listen。QUIC、启用 TLS 的 TCP 与 wss:// 必须提供对应 security。明文 TCP、IPC 与 ws:// 不满足 nnrps:// 应用 endpoint。
Provider Routes
| 类型 | 冻结属性 |
|---|---|
NnrpClientProviderRoute | ProviderEndpoint、Security |
NnrpServerProviderRoute | ProviderEndpoint、Security |
NnrpClientOptions.ProviderRoutes 与 NnrpServerOptions.ProviderRoutes 是按 TransportId 索引的 只读 dictionary。每条 route 只持有一个 carrier 的 locator 与 security。Role-wide ProviderEndpoint 与 Security 不属于 Preview4 宿主 API。
Provider 契约
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);
}NnrpTransportConnection 和 NnrpTransportListener 是 opaque、可释放的 ownership value。它们 可以把 carrier ownership 转交给角色 runtime,但不会向应用暴露 FFI handle、pointer 或 native buffer。
| Options 类型 | 冻结属性 |
|---|---|
NnrpTransportConnectOptions | Endpoint、ProviderEndpoint、Security、MaxPacketBytes、TimeoutMilliseconds |
NnrpTransportListenOptions | Endpoint、ProviderEndpoint、Security、MaxPacketBytes、TimeoutMilliseconds |
NnrpTransportProbeOptions | connect options 加 SampleCount、PayloadBytes、IncludeWarmup |
Provider Metadata
| C# 类型 | 冻结属性或值 |
|---|---|
NnrpTransportProviderKind | PureRust、NativeDynamic、Wasm |
NnrpTransportProviderCost | ModelId: ushort、Units: ulong |
NnrpTransportProviderLimits | MaxFrameBytes: ulong |
NnrpTransportProviderLimitation | RequiresUdp、RequiresTcp、LocalHostOnly、NativeHostOnly、BrowserHostOnly、UnixDomainSocket、WindowsNamedPipe |
NnrpTransportProviderMetadata | Id: string、Cost: NnrpTransportProviderCost、PreferenceRank: ushort、Limits: NnrpTransportProviderLimits、Limitations: IReadOnlyList<NnrpTransportProviderLimitation> |
NnrpTransportProviderDescriptor | Name: string、Version: string、TransportId: TransportId、Kind: NnrpTransportProviderKind、Available: bool、LibraryPath: string?、Metadata: NnrpTransportProviderMetadata、Diagnostic: string? |
NnrpTransportCandidateReadiness | TransportId: TransportId、ProviderId: string、RouteResolved: bool、SecuritySatisfied: bool、Diagnostic: string? |
NnrpTransportProbeState | NotRun、Succeeded、Failed、Missing |
NnrpTransportProbeMetrics | SampleCount: uint、SuccessCount: uint、MedianThroughputBytesPerSecond: ulong、MedianRttMicroseconds: ulong |
NnrpTransportProbeObservation | TransportId: TransportId、ProviderId: string、State: NnrpTransportProbeState、Metrics: NnrpTransportProbeMetrics?、Diagnostic: string?;state 只能是 Succeeded 或 Failed |
NnrpTransportRejectionReason | PolicyDisallowed、LocalUnavailable、PeerUnsupported、LimitExceeded、RouteUnresolved、SecurityUnsatisfied、ProbeMissing、ProbeFailed |
NnrpTransportCandidate | TransportId: TransportId、Provider: NnrpTransportProviderMetadata、LocalAvailable: bool、PeerSupported: bool、WithinLimits: bool、ProbeState: NnrpTransportProbeState、Probe: NnrpTransportProbeMetrics?、SelectionRank: uint?、RejectionReason: NnrpTransportRejectionReason?、Diagnostic: string? |
NnrpTransportSelection | SelectedProvider: NnrpTransportProviderDescriptor、有序 Candidates: IReadOnlyList<NnrpTransportCandidate>、Policy: TransportPolicy、Diagnostic: string? |
NnrpTransportSelectionException | Code: NnrpTransportSelectionErrorCode、Policy: 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 的输入:
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
PeerSupportedTransports | IReadOnlyCollection<TransportId> | 是 | Peer 声明的 carrier 交集。 |
Policy | TransportPolicy | 否 | 默认值为 Auto。 |
RequestedMaxFrameBytes | ulong? | 否 | 对照 Provider.Limits.MaxFrameBytes 校验的 workload limit。 |
CandidateReadiness | IReadOnlyCollection<NnrpTransportCandidateReadiness> | 是 | 每个已注册 provider 的 route/security evidence。 |
ProbeObservations | IReadOnlyCollection<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。 |
安装的一方包会注册 NnrpNativeTcpTransportProvider、NnrpNativeQuicTransportProvider、 NnrpNativeIpcTransportProvider 或 NnrpNativeWebSocketTransportProvider 到内部默认 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.Tcp | NnrpNativeTcpTransportProvider | 仅 TCP |
Nnrp.Transport.Quic | NnrpNativeQuicTransportProvider | 仅 QUIC |
Nnrp.Transport.Ipc | NnrpNativeIpcTransportProvider | 仅 IPC |
Nnrp.Transport.WebSocket | NnrpNativeWebSocketTransportProvider | 仅 WebSocket |
每个包持有自己的具体 provider descriptor 与 transport-scoped Rust artifact。具体 provider 暴露 connect、 listen 与 probe;Nnrp.NativeBridge 统一持有粗粒度 FFI 调用与 native handle 生命周期机制。client 与 server 包不携带 transport artifact。
诊断 Framed Transport
INnrpMessageSender、INnrpMessageReceiver、INnrpMessageTransport 和 NnrpTcpMessageTransport 只属于底层 packet 诊断/自定义 carrier 契约。它们不参与生产 provider 选择,也不是 native artifact 缺失时的 fallback。