WSL WslcSDK 端口映射 API 详解:WslcSetContainerSettingsPortMappings 使用指南
2026/9/10 1:46:36 网站建设 项目流程

WSL WslcSDK 端口映射 API 详解:WslcSetContainerSettingsPortMappings 使用指南

【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL

WSL(Windows Subsystem for Linux)的 WslcSDK 提供了一套用于管理 WSL 容器的 C API,其中WslcSetContainerSettingsPortMappings负责在容器创建前设置宿主机与容器之间的端口映射规则,是搭建"Windows 宿主机 ⇄ WSL 容器"网络服务暴露链路的关键接口。本文将基于官方 API 参考文档与仓库源码、测试用例,完整讲解该函数的签名、参数语义、底层校验逻辑、完整调用流程与当前实现的限制,帮助你正确地将容器内服务映射到 Windows 宿主机的指定端口与地址。

1. API 概览

WslcSetContainerSettingsPortMappings是 WslcSDK 中一组 "OPTIONAL CONTAINER SETTINGS"(可选容器设置)API 之一,用于为尚未创建的容器批量写入端口映射配置。完整声明定义在头文件 src/windows/WslcSDK/wslcsdk.h#L257-L260 中,同时作为导出符号列于 src/windows/WslcSDK/wslcsdk.def:

STDAPI WslcSetContainerSettingsPortMappings( _In_ WslcContainerSettings* containerSettings, _In_reads_opt_(portMappingCount) const WslcContainerPortMapping* portMappings, _In_ uint32_t portMappingCount);

参数说明

参数类型方向含义
containerSettingsWslcContainerSettings*in由 WslcInitContainerSettings 初始化得到的容器设置句柄(不透明结构)
portMappingsconst WslcContainerPortMapping*in, optional指向端口映射数组的指针,可为NULL(用于清空映射)
portMappingCountuint32_tin端口映射条目的数量

返回值类型为HRESULTS_OK表示设置成功;参数非法时返回E_INVALIDARG;暂不支持的协议返回E_NOTIMPL(详见下文"源码级实现剖析")。

该 API 只是把映射"写入"容器设置对象,真正的端口监听与转发发生在 WslcCreateContainer / WslcStartContainer 之后——即端口映射属于"创建期配置",必须在创建容器之前完成设置。

2. 前置知识:映射结构与协议枚举

WslcSetContainerSettingsPortMappings的输入数组元素类型为WslcContainerPortMapping,完整定义见 doc/docs/api-reference/c/structures/wslccontainerportmapping.md:

typedef struct WslcContainerPortMapping { _In_ uint16_t windowsPort; // Port on Windows host _In_ uint16_t containerPort; // Port inside container _In_ WslcPortProtocol protocol; // TCP or UDP // if you want to override the default binding address _In_opt_ struct sockaddr_storage* windowsAddress; // accepts ipv4/6 } WslcContainerPortMapping;
字段类型说明
windowsPortuint16_tWindows 宿主机上对外监听的端口
containerPortuint16_t容器内部服务的端口
protocolWslcPortProtocol传输协议(TCP 或 UDP)
windowsAddressstruct sockaddr_storage*可选,覆盖宿主机默认绑定地址,支持 IPv4/IPv6

其中protocol字段使用枚举 WslcPortProtocol:

typedef enum WslcPortProtocol { WSLC_PORT_PROTOCOL_TCP = 0, WSLC_PORT_PROTOCOL_UDP = 1 } WslcPortProtocol;
枚举值数值说明
WSLC_PORT_PROTOCOL_TCP0TCP 协议(当前唯一受支持的值)
WSLC_PORT_PROTOCOL_UDP1UDP 协议(当前仓库实现中返回E_NOTIMPL

containerSettings本身是不透明结构(见 doc/docs/api-reference/c/structures/wslccontainersettings.md),以对齐字节数组形式隐藏内部布局,调用方只能通过WslcInitContainerSettings初始化和一系列WslcSetContainerSettings*函数来填充。这正是 WslcSDK 的设计模式:先初始化、再逐项设置、最后创建容器

3. 基础使用示例:将容器 80 端口映射到宿主机 8080

官方 API 参考文档(wslcsetcontainersettingsportmappings.md)给出了最核心的单条映射示例,完整继承如下:

WslcContainerPortMapping portMappings[1] = { 0 }; portMappings[0].windowsPort = (uint16_t)8080; portMappings[0].containerPort = (uint16_t)80; portMappings[0].protocol = WSLC_PORT_PROTOCOL_TCP; portMappings[0].windowsAddress = NULL; HRESULT hr = WslcSetContainerSettingsPortMappings( &containerSettings, portMappings, (uint32_t)_countof(portMappings));

这段代码的语义是:将 Windows 宿主机的 8080 端口(默认绑定地址)转发到容器内的 80 端口,走 TCP 协议windowsAddress = NULL表示使用默认绑定地址,不覆盖宿主机的监听地址。

将其放入完整生命周期中,一个最小可运行的调用序列为:

// 1. 初始化容器设置 WslcContainerSettings containerSettings; HRESULT hr = WslcInitContainerSettings("python:3.12-alpine", &containerSettings); if (FAILED(hr)) { /* 处理错误 */ } // 2. (可选)设置容器名称、网络模式等 hr = WslcSetContainerSettingsName(&containerSettings, "my-web-container"); hr = WslcSetContainerSettingsNetworkingMode(&containerSettings, WSLC_CONTAINER_NETWORKING_MODE_BRIDGED); // 3. 设置端口映射 WslcContainerPortMapping portMappings[1] = { 0 }; portMappings[0].windowsPort = (uint16_t)8080; portMappings[0].containerPort = (uint16_t)80; portMappings[0].protocol = WSLC_PORT_PROTOCOL_TCP; portMappings[0].windowsAddress = NULL; hr = WslcSetContainerSettingsPortMappings(&containerSettings, portMappings, (uint32_t)_countof(portMappings)); if (FAILED(hr)) { /* 处理错误 */ } // 4. 创建并启动容器(此时端口映射才会真正生效) // WslcContainer container = nullptr; // hr = WslcCreateContainer(session, &containerSettings, &container, nullptr); // hr = WslcStartContainer(container, WSLC_CONTAINER_START_FLAG_ATTACH, nullptr);

注意:从源码测试可以看出,若网络模式为WSLC_CONTAINER_NETWORKING_MODE_NONE时仍设置端口映射,WslcCreateContainer会返回E_INVALIDARG(见下文"边界行为与错误处理"),因此配置端口映射时务必搭配支持端口转发的网络模式(如WSLC_CONTAINER_NETWORKING_MODE_BRIDGED)。

4. 绑定地址覆盖:IPv4 与 IPv6

当需要把宿主机监听限制到特定地址(而不是全部网卡)时,通过windowsAddress字段传入struct sockaddr_storage*。参考 test/windows/WslcSdkTests.cpp#L916-L996 中的两个功能测试,可以写出标准的 IPv4 绑定写法:

sockaddr_storage addr4{}; auto* sin4 = reinterpret_cast<sockaddr_in*>(&addr4); sin4->sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &sin4->sin_addr); WslcContainerPortMapping mapping{}; mapping.windowsPort = 12343; mapping.containerPort = 8000; mapping.protocol = WSLC_PORT_PROTOCOL_TCP; mapping.windowsAddress = &addr4; hr = WslcSetContainerSettingsPortMappings(&containerSettings, &mapping, 1);

IPv6 绑定(如仅允许回环地址::1访问)写法相同,只需把地址族切换为AF_INET6

sockaddr_storage addr6{}; auto* sin6 = reinterpret_cast<sockaddr_in6*>(&addr6); sin6->sin6_family = AF_INET6; inet_pton(AF_INET6, "::1", &sin6->sin6_addr); WslcContainerPortMapping mapping{}; mapping.windowsPort = 12344; mapping.containerPort = 8000; mapping.protocol = WSLC_PORT_PROTOCOL_TCP; mapping.windowsAddress = &addr6; hr = WslcSetContainerSettingsPortMappings(&containerSettings, &mapping, 1);

5. 源码级实现剖析:参数校验与内部存储

WslcSetContainerSettingsPortMappings的实现位于 src/windows/WslcSDK/wslcsdk.cpp#L1041-L1064,逻辑非常清晰,可以归纳为三步。

第一步:取值并做空指针/计数一致性校验。

auto internalType = CheckAndGetInternalType(containerSettings); RETURN_HR_IF(E_INVALIDARG, (portMappings == nullptr && portMappingCount != 0) || (portMappings != nullptr && portMappingCount == 0));

portMappingsportMappingCount必须"同生共死":指针为空且数量非零、或指针非空且数量为零,都会立即返回E_INVALIDARG。这与测试 test/windows/WslcSdkTests.cpp#L841-L854 中两个负面用例一一对应。

第二步:逐条校验每条映射的地址族与协议。

for (uint32_t i = 0; i < portMappingCount; ++i) { if (portMappings[i].windowsAddress != nullptr) { const auto family = portMappings[i].windowsAddress->ss_family; RETURN_HR_IF_MSG( E_INVALIDARG, family != AF_INET && family != AF_INET6, "Unsupported address family: %d at port mapping index %u", family, i); } RETURN_HR_IF_MSG( E_NOTIMPL, portMappings[i].protocol != 0, "Unsupported protocol: %d at port mapping index %u", portMappings[i].protocol, i); }
  • 地址族限制windowsAddress只接受AF_INET(IPv4)与AF_INET6(IPv6),其他地址族(如AF_UNIX)一律返回E_INVALIDARG,错误消息会带出具体的地址族编号与数组下标,便于定位出错条目。测试 test/windows/WslcSdkTests.cpp#L998-L1013 用AF_UNIX验证了这条路径。
  • 协议限制:目前实现只接受WSLC_PORT_PROTOCOL_TCP(枚举值为 0),传入 UDP(枚举值为 1)会返回E_NOTIMPL。这一限制也被记录在 doc/docs/api-reference/c/not-yet-implemented-apis.md 中,属于"已声明但尚未实现"的能力清单——即当前仓库中端口映射仅支持 TCP。

第三步:将映射数组及数量写入内部类型并返回S_OK

internalType->ports = portMappings; internalType->portsCount = portMappingCount; return S_OK;

注意ports保存的是调用方传入的指针,因此调用方必须在容器真正创建之前保持该数组内存有效,这与整个 WslcSDK "设置对象即描述符" 的设计一致。

6. 边界行为与错误处理

综合源码实现与测试用例(test/windows/WslcSdkTests.cpp#L839-L1014),该 API 的全部边界行为可归纳为下表:

场景行为依据
portMappings == NULLportMappingCount != 0返回E_INVALIDARGwslcsdk.cpp#L1046;测试 #L845
portMappings != NULLportMappingCount == 0返回E_INVALIDARG同上;测试 #L853
portMappings == NULLportMappingCount == 0成功(S_OK),等价于清空端口映射测试 #L860
windowsAddress->ss_family不是AF_INET/AF_INET6返回E_INVALIDARGwslcsdk.cpp#L1050-L1054;测试 #L1012
protocol不是WSLC_PORT_PROTOCOL_TCP(0)返回E_NOTIMPLwslcsdk.cpp#L1056-L1057
网络模式为 NONE 却配置端口映射设置 API 本身成功,但WslcCreateContainer返回E_INVALIDARG测试 #L863-L878

最后一条特别值得注意:"设置成功"不等于"创建成功"。网络模式与端口映射的语义冲突被推迟到容器创建阶段才暴露,因此最佳实践是在调用 WslcCreateContainer 后统一检查其返回值与errorMessage输出参数。

7. 在 WinRT 封装层中的调用方式

WslcSDK 除了 C 接口外,还在 src/windows/WslcSDK/winrt 下提供了 WinRT 投影层。其中 src/windows/WslcSDK/winrt/ContainerSettings.cpp#L269-L284 展示了该 API 在封装侧的典型用法——先将 WinRT 集合中的PortMapping投影对象批量转换为底层结构体数组,再一次性提交:

if (m_portMappings.Size() > 0) { m_portMappingsStructs.clear(); m_portMappingsStructs.reserve(m_portMappings.Size()); for (auto const& portMapping : m_portMappings) { if (!portMapping) { throw winrt::hresult_error(E_POINTER, L"Port mappings collection contains a null element"); } m_portMappingsStructs.push_back(GetStruct(portMapping)); } winrt::check_hresult(WslcSetContainerSettingsPortMappings( m_containerSettings.get(), m_portMappingsStructs.data(), static_cast<uint32_t>(m_portMappingsStructs.size()))); }

可以看到,封装层在调用前做了两个额外的约定:映射集合为空(Size() == 0)时不会调用本 API(保持默认无映射);集合中出现空元素则直接抛出E_POINTER。同时通过winrt::check_hresult将任何失败HRESULT转换为 WinRT 异常,符合 WinRT 侧的惯例。

8. 与其他容器 API 的关系与调用顺序

WslcSetContainerSettingsPortMappings属于 Container APIs 中 "OPTIONAL CONTAINER SETTINGS" 一组。与同组的兄弟 API(WslcSetContainerSettingsNameWslcSetContainerSettingsInitProcessWslcSetContainerSettingsNetworkingModeWslcSetContainerSettingsHostNameWslcSetContainerSettingsDomainNameWslcSetContainerSettingsFlagsWslcSetContainerSettingsVolumesWslcSetContainerSettingsNamedVolumes)一样,它们都遵循相同的生命周期约定:

WslcInitContainerSettings │ ▼ WslcSetContainerSettings* (按需多次调用,端口映射是其中之一) │ ▼ WslcCreateContainer ──► WslcStartContainer ──► WslcGetContainerInitProcess / WslcCreateContainerProcess │ ▼ WslcStopContainer ──► WslcDeleteContainer ──► WslcReleaseContainer

端口映射的"写入期"严格位于WslcInitContainerSettings之后、WslcCreateContainer之前;一旦容器创建完成,修改容器设置对象不会再影响已创建的容器。从 Container APIs 索引 可以看到,端口映射只是众多可选设置之一,实际项目中通常与网络模式、初始化进程、卷挂载等组合使用。

9. 当前限制与注意事项

基于 not-yet-implemented-apis.md 与源码校验逻辑,使用本 API 时需注意:

  1. 仅支持 TCP:传入WSLC_PORT_PROTOCOL_UDP会得到E_NOTIMPL。虽然 WslcPortProtocol 枚举同时定义了 TCP/UDP,但当前仓库实现只接受 TCP(数值 0)。
  2. 仅支持 IPv4/IPv6 地址族windowsAddress传入其他地址族(如AF_UNIX)会得到E_INVALIDARG,且错误信息包含具体的下标索引。
  3. 指针与计数必须配对NULL指针 + 非零计数、非空指针 + 零计数均属非法参数;NULL+ 零计数是合法的"清空映射"写法。
  4. 内存生命周期WslcSetContainerSettingsPortMappings内部保存的是调用方数组指针,容器创建前请勿释放或改写该数组。
  5. 与网络模式的配合:设置端口映射前请确认网络模式不是WSLC_CONTAINER_NETWORKING_MODE_NONE,否则容器创建阶段会失败。
  6. 回调检查返回值:设置阶段成功不代表创建阶段成功,务必检查WslcCreateContainer的返回值与errorMessage输出。

10. 小结

WslcSetContainerSettingsPortMappings是 WSL WslcSDK 中暴露容器网络服务到 Windows 宿主机的端口映射设置入口。通过本篇文章你可以掌握:函数签名与参数语义、WslcContainerPortMapping结构与WslcPortProtocol枚举的完整字段、官方示例及 IPv4/IPv6 绑定地址覆盖写法、源码层的三类参数校验规则(指针配对、地址族、协议),以及仓库测试用例所覆盖的全部边界行为。在实际开发中,建议将本 API 与 WslcInitContainerSettings、WslcSetContainerSettingsNetworkingMode 和 WslcCreateContainer 组合使用,并牢记当前实现仅支持 TCP、UDP 映射属于未实现能力。

【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询