> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 首选本地 UDP 多人游戏端口网络 API

> 首选本地用户数据报协议 (UDP) 多人游戏端口网络 API

本主题帮助你了解如何使用首选本地用户数据报协议 (UDP) 多人游戏端口 API 来提升多人游戏可靠性。所有 XBOX 主机迭代都允许你使用 *UDP 3074*。这是一个公开注册、众所周知的多人游戏网络流量端口。Microsoft 游戏开发工具包 (GDK) 游戏也不例外，可以使用首选本地 UDP 多人游戏端口网络 API 访问该特殊端口。

首选本地 UDP 多人游戏端口是指在后续 [socket bind](https://learn.microsoft.com/windows/desktop/api/winsock/nf-winsock-bind) 操作中使用的本地端口，而不是远程设备用来连接本地设备的公共端口。前者仅对 UDP 流量有意义，而不适用于 TCP 或 HTTP 流量，因为它专门针对多人游戏中的实时游戏网络流。

历史上，此端口一直被限定为 UDP 3074。但近年来引入了回退逻辑以提升该端口的可靠性。此外，用户还可以手动配置该端口以适应其独特的网络配置。因此，在 Microsoft 游戏开发工具包 (GDK) 游戏中硬编码 UDP 3074 已不再安全。Microsoft 游戏开发工具包 (GDK) 游戏应动态查询当前配置的端口。

有三种方式可用于获取首选本地 UDP 多人游戏端口。

* **阻塞式：** [XNetworkingQueryPreferredLocalUdpMultiplayerPort](/reference/networking/xnetworking/functions/xnetworkingquerypreferredlocaludpmultiplayerport)
* **异步式：** [XNetworkingQueryPreferredLocalUdpMultiplayerPortAsync](/reference/networking/xnetworking/functions/xnetworkingquerypreferredlocaludpmultiplayerportasync)
* **通知式：** [XNetworkingRegisterPreferredLocalUdpMultiplayerPortChanged](/reference/networking/xnetworking/functions/xnetworkingregisterpreferredlocaludpmultiplayerportchanged)

这三种方式提供相同的基本功能。Microsoft 游戏开发工具包 (GDK) 游戏可根据具体需求和使用场景调用其中任意一种（或多种组合）。

我们强烈建议所有 Microsoft 游戏开发工具包 (GDK) 游戏在其主要游戏流量上使用首选端口。该端口针对点对点网络拓扑和客户端/服务器网络拓扑都进行了优化。Microsoft 游戏开发工具包 (GDK) 平台确保这一特定端口最有可能适用于每个用户的具体网络环境。使用该端口能最大程度地利用平台的客户支持与诊断流程，提升标准化 NAT (网络地址转换) 兼容性，提供标准化的 UPnP™ 认证设备功能，并让 QoS 路由器与 ISP 算法将数据包识别为实时敏感数据。

对于依赖点对点网络拓扑的游戏，此首选端口尤为重要。它是唯一允许入站 UDP 数据包在不进行防火墙打洞的情况下穿过防火墙的端口。依赖点对点网络拓扑的 Microsoft 游戏开发工具包 (GDK) 游戏仍需自行提供公共 IP 地址和端口发现能力，并为具有中等或严格 NAT 类型的客户端提供 NAT 打洞方案。首选端口能提升这些技术的成功率，但不能替代它们。

使用客户端/服务器网络拓扑的游戏也能受益于该端口。故障排查、UPnP™ 和数据包识别对于医院、酒店和大学宿舍中常见的强制门户及其他基于源的过滤方式仍然适用。

首选端口应像任何其他端口一样对待，与 [Windows Sockets 2 (Winsock)](https://learn.microsoft.com/windows/desktop/WinSock/windows-sockets-start-page-2) API 一同使用。游戏应同时在此端口上绑定 IPv4 与 IPv6，或使用双栈套接字，并绑定到 `INADDR_ANY`/`in6addr_any` 地址。

## 处理套接字失败

不保证返回的端口一定能与特定服务器或对等方成功建立套接字连接。应执行常规的游戏重试和回退逻辑。每当套接字关闭并重新打开时，游戏都应重新查询最近的首选本地 UDP 多人游戏端口，因为端口可能随时间变化。

## 网络初始化

`XNetworkingQueryPreferredLocalUdpMultiplayerPort` API 的三种方式（阻塞、异步和通知式）在游戏启动和恢复时都会阻塞或延迟完成/通知，直到网络完成初始化。你可以按 [检测网络初始化状态](/build/console-features/networking/initialization-connectivity-networking) 中的概述单独等待网络初始化，也可以调用这些 API 并等待其返回。

<a id="SuspendResume" />

## 挂起与恢复

与任何其他套接字一样，绑定到首选本地 UDP 多人游戏端口的套接字应在挂起时关闭，并在恢复时等待网络初始化完成后重新创建。你应通过 `RegisterAppStateChangeNotification` 注册挂起与恢复事件。在恢复时，应假定首选本地 UDP 多人游戏端口可能已变更，因此要么监听首选本地 UDP 多人游戏端口的变化，要么在创建新套接字时重新查询。有关 WinSock 挂起与恢复处理的更多信息，请参阅 [Winsock 中的挂起与恢复](/build/console-features/networking/game-mesh/winsock-intro-networking#SuspendResume)。

## 首选本地 UDP 多人游戏端口的变更

游戏可以使用 [XNetworkingRegisterPreferredLocalUdpMultiplayerPortChanged](/reference/networking/xnetworking/functions/xnetworkingregisterpreferredlocaludpmultiplayerportchanged) API 监听首选本地 UDP 多人游戏端口的变化。

系统会尽力确保在游戏运行期间首选本地 UDP 多人游戏端口不发生变化。但在某些不可避免的情况下，由于用户的外部网络条件发生变化，导致现有套接字流失效时，端口会发生变化。当 [网络连接级别](/build/console-features/networking/initialization-connectivity-networking) 变化时或作为游戏挂起/恢复周期的一部分时，端口尤其容易变化。

首选本地 UDP 多人游戏端口变化时，来自未来对等方的额外入站连接可能会在之前的任何首选端口上被阻止。这可能不会在套接字层导致失败。但是游戏最终可能无法在绑定到之前任何首选端口的任何套接字上接收数据包。

与现有对等方之间发送和接收的数据包可能继续正常工作。首选本地 UDP 多人游戏端口变化的通知对任何正在进行的游戏会话未必是致命的。

发生变化通知时，游戏应迁移到绑定在新首选端口上的新套接字。此迁移应尽早进行，且不应中断任何现有玩法。要检测连接丢失并重试套接字连接，游戏应始终使用最新的首选端口。

### 测试首选本地 UDP 多人游戏端口的更改

按以下步骤更改首选本地 UDP 多人游戏端口。

1. 在游戏运行时，打开 **XBOX Guide**。转到 **Settings** 应用。
2. 在 **General** 选项卡上，选择 **Network settings**。
3. 选择 **Advanced settings**，然后选择 **Alternate port selection**。
4. 将端口选择设置为 **Manual**。使用下拉菜单选择端口。
5. 端口选择立即生效，并向游戏发送相应通知。
6. 测试完成后，将端口选择设置回 **Automatic**，使端口行为恢复默认。

<Note>
  当进入 Settings 应用时，游戏受到约束但仍在运行，即使你的游戏不可见，也会立即收到端口变更通知。如果你打开 Settings 应用超过 10 分钟未切换回游戏，游戏将被挂起。
</Note>

## 安全性

绑定到首选本地 UDP 多人游戏端口的套接字的行为与任何其他套接字完全相同。特别是，此套接字并不会提供任何额外的安全性。游戏应按通信安全最佳实践在绑定到首选本地 UDP 多人游戏端口的套接字之上使用自己的安全通信协议。有关更多信息，请参阅 [通信安全概述 (NDA 主题)](/build/game-principles/security/communication-security-overview)。

## 点对点

首选本地 UDP 多人游戏端口提供了构建点对点网络最好的已知端口。它以最佳方式配置，允许通过用户的 NAT 层的入站连接。但游戏仍负责执行 NAT 穿越，包括以下内容。

* 检测 NAT 类型
* 检测并交换设备的公共 IP 地址与端口
* NAT 打洞与穿越

## Azure PlayFab Party

在内部，[PlayFab Party](/build/console-features/networking/game-mesh/playfab-party-intro-networking) 默认使用首选本地 UDP 多人游戏端口。可通过 PlayFab Party API 配置。除非 PlayFab Party 端口发生变化，否则游戏不应直接绑定到首选本地 UDP 多人游戏端口。

## 使用示例

以下示例展示了如何将双栈套接字绑定到首选本地 UDP 多人游戏端口。为简洁起见，示例使用了阻塞式 [XNetworkingQueryPreferredLocalUdpMultiplayerPort](/reference/networking/xnetworking/functions/xnetworkingquerypreferredlocaludpmultiplayerport) 调用，并假定游戏此前已等待网络就绪并已调用过 [WSAStartup](https://learn.microsoft.com/windows/desktop/api/winsock/nf-winsock-wsastartup)。

```cpp theme={null}
HRESULT
CreateAndBindMultiplayerSocket(
    _Out_ SOCKET* multiplayerSocket
    )
{
    HRESULT hr;
    SOCKET resultSocket = INVALID_SOCKET;

    uint16_t port;
    hr = XNetworkingQueryPreferredLocalUdpMultiplayerPort(&port);
    if (FAILED(hr))
    {
        goto Failure;
    }

    resultSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    if (resultSocket == INVALID_SOCKET)
    {
        hr = HRESULT_FROM_WIN32(WSAGetLastError());
        goto Failure;
    }

    // Enable both IPv4 and IPv6 on this socket.
    int v6only = 0;
    if (setsockopt(resultSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&v6only, sizeof(v6only)) == SOCKET_ERROR)
    {
        hr = HRESULT_FROM_WIN32(WSAGetLastError());
        goto Failure;
    }

    sockaddr_in6 sa;
    ZeroMemory(&sa, sizeof(sa));
    sa.sin6_family = AF_INET6;
    sa.sin6_port = htons(port);
    sa.sin6_addr = in6addr_any;
    if (bind(resultSocket, (const sockaddr*)&sa, sizeof(sa)) == SOCKET_ERROR)
    {
        hr = HRESULT_FROM_WIN32(WSAGetLastError());
        goto Failure;
    }

    *multiplayerSocket = resultSocket;

Exit:

    return hr;

Failure:

    if (resultSocket != INVALID_SOCKET)
    {
        (void)closesocket(resultSocket);
    }

    goto Exit;
}
```

## 参考 API 文档

* [Xnetworking (API 内容)](/reference/networking/xnetworking/xnetworking_members)
  * 函数
    * [XNetworkingQueryPreferredLocalUdpMultiplayerPort](/reference/networking/xnetworking/functions/xnetworkingquerypreferredlocaludpmultiplayerport)
    * [XNetworkingQueryPreferredLocalUdpMultiplayerPortAsync](/reference/networking/xnetworking/functions/xnetworkingquerypreferredlocaludpmultiplayerportasync)
    * [XNetworkingRegisterPreferredLocalUdpMultiplayerPortChanged](/reference/networking/xnetworking/functions/xnetworkingregisterpreferredlocaludpmultiplayerportchanged)

## 另请参阅

[首选本地 UDP 多人游戏端口 API 参考 (XNetworking)](/reference/networking/xnetworking/xnetworking_members)

[Windows Sockets 2 (Winsock)](https://learn.microsoft.com/windows/desktop/WinSock/windows-sockets-start-page-2)

[通信安全概述 (NDA 主题)](/build/game-principles/security/communication-security-overview)
