
文档教程游戏开发【免费下载链接】godot-docsGodot Engine official documentation项目地址https://gitcode.com/GitHub_Trending/go/godot-docs点击查看免费下载本文基于 Godot Engine 官方文档godot-docs仓库中的 DTLSServer 类参考系统讲解如何在 Godot 中搭建基于 DTLSDatagram Transport Layer Security的加密 UDP 服务器。你将掌握 DTLSServer 的两个核心方法setup与take_connection的使用方式、它与 PacketPeerUDP、UDPServer、PacketPeerDTLS、TLSOptions 等配套类的协作关系并拿到一份可直接运行的 GDScript / C# 服务端与客户端完整示例为实时对战、语音通信等低延迟场景提供加密传输方案。DTLSServer 是什么DTLSServer 是一个帮助实现 DTLS 服务器端的辅助类继承自RefCounted再往上为Object。它在文档中的定位非常明确This class is used to store the state of a DTLS server.也就是说DTLSServer 本身并不直接收发 UDP 报文而是存储 DTLS 服务器端的状态与 cookie。当你调用 setup() 完成配置后它会把连接上来的 PacketPeerUDP 转换为 PacketPeerDTLS并通过 take_connection() 以 DTLS 客户端的形式接纳它们。文档也明确说明为什么需要这些状态和 cookie 属于 DTLS 协议本身的范畴超出该类文档的讨论范围——但对于理解 50% 连接失败现象很有帮助下文会解释。从整体架构看一个典型的 Godot DTLS 服务端由以下组件协作完成组件角色UDPServer打开 UDP 监听 socketpoll()后把新到达的地址/端口组合作为待处理连接暴露出来PacketPeerUDPUDPServer.take_connection()返回的、已定向到某个客户端地址的 UDP peerDTLSServer持有 DTLS 状态与 cookie把 UDP peer 包装成加密的 PacketPeerDTLSPacketPeerDTLS每个已加密连接的句柄需周期性poll()通过继承自 PacketPeer 的put_packet/get_packet收发数据TLSOptions服务器端密钥与证书的配置载体由setup()传入工作流程与 DTLS 握手状态机在深入代码前先理清数据流UDPServer.listen(port)打开 UDP socket每帧调用UDPServer.poll()处理新报文来自未知地址/端口组合的报文会被登记为 pending connection通过UDPServer.is_connection_available()与take_connection()取出新的PacketPeerUDP调用DTLSServer.take_connection(peer)对该 UDP peer 发起 DTLS 握手返回PacketPeerDTLS对返回的PacketPeerDTLS持续调用poll()驱动握手与后续传输直到状态变为STATUS_CONNECTED。这里有一个文档反复强调、也是最容易让新手困惑的要点由于 DTLS 的 cookie 交换机制大约 50% 的新连接在初次握手时会失败状态不是STATUS_HANDSHAKING。这属于正常现象代码里应跳过这些连接而不是报错退出。其本质是 DTLS 协议用 cookie 来抵御基于 UDP 的放大攻击Amplification Attack——服务器先向客户端签发 cookie客户端需要携带该 cookie 重新发起握手因此第一轮报文往往无法直接建立会话。PacketPeerDTLS的状态枚举定义见 class_packetpeerdtls.rst就是整个握手/连接过程的状态机常量值含义STATUS_DISCONNECTED0已断开STATUS_HANDSHAKING1正在与远端执行握手STATUS_CONNECTED2已与远端建立连接STATUS_ERROR3通用错误状态STATUS_ERROR_HOSTNAME_MISMATCH4证书域名与验证请求的域名不匹配服务端在take_connection()后应检查状态是否为STATUS_HANDSHAKING来决定是否接受该连接客户端则轮询直到STATUS_CONNECTED。服务端实现完整示例以下是 class_dtlsserver.rst 中官方提供的服务端示例GDScript 与 C# 双版本完整继承了文档原样并配合下文注释理解每一步。GDScript 版本server_node.gd# server_node.gd extends Node var dtls DTLSServer.new() var server UDPServer.new() var peers [] func _ready(): server.listen(4242) var key load(key.key) # Your private key. var cert load(cert.crt) # Your X509 certificate. dtls.setup(TlsOptions.server(key, cert)) func _process(delta): while server.is_connection_available(): var peer server.take_connection() var dtls_peer dtls.take_connection(peer) if dtls_peer.get_status() ! PacketPeerDTLS.STATUS_HANDSHAKING: continue # It is normal that 50% of the connections fails due to cookie exchange. print(Peer connected!) peers.append(dtls_peer) for p in peers: p.poll() # Must poll to update the state. if p.get_status() PacketPeerDTLS.STATUS_CONNECTED: while p.get_available_packet_count() 0: print(Received message from client: %s % p.get_packet().get_string_from_utf8()) p.put_packet(Hello DTLS client.to_utf8_buffer())C# 版本ServerNode.cs// ServerNode.cs using Godot; public partial class ServerNode : Node { private DtlsServer _dtls new DtlsServer(); private UdpServer _server new UdpServer(); private Godot.Collections.ArrayPacketPeerDtls _peers []; public override void _Ready() { _server.Listen(4242); var key GD.LoadCryptoKey(key.key); // Your private key. var cert GD.LoadX509Certificate(cert.crt); // Your X509 certificate. _dtls.Setup(TlsOptions.Server(key, cert)); } public override void _Process(double delta) { while (_server.IsConnectionAvailable()) { PacketPeerUdp peer _server.TakeConnection(); PacketPeerDtls dtlsPeer _dtls.TakeConnection(peer); if (dtlsPeer.GetStatus() ! PacketPeerDtls.Status.Handshaking) { continue; // It is normal that 50% of the connections fails due to cookie exchange. } GD.Print(Peer connected!); _peers.Add(dtlsPeer); } foreach (var p in _peers) { p.Poll(); // Must poll to update the state. if (p.GetStatus() PacketPeerDtls.Status.Connected) { while (p.GetAvailablePacketCount() 0) { GD.Print($Received Message From Client: {p.GetPacket().GetStringFromUtf8()}); p.PutPacket(Hello DTLS Client.ToUtf8Buffer()); } } } } }关键点逐行解读server.listen(4242)让UDPServer在 4242 端口打开 UDP socket。listen(port, bind_address *)支持第二个参数限定监听地址规则与PacketPeerUDP.bind()一致*监听全部地址0.0.0.0/::分别限定 IPv4 / IPv6也可指定具体 IP。dtls.setup(TlsOptions.server(key, cert))用私钥与 X.509 证书初始化 DTLS 服务器。TLSOptions.server(key, certificate)是静态工厂方法key为 CryptoKeycertificate为 X509Certificate。注意文档提示证书应包含一直到签名 CA 的完整证书链多个证书文件可用普通文本编辑器拼接。server.take_connection()取出第一个 pending connection返回定向到对应地址/端口的PacketPeerUDP无新连接时返回null因此需配合is_connection_available()使用。dtls.take_connection(peer)对已连接的 UDP peer 尝试发起 DTLS 握手。必须检查返回 peer 的状态由于 cookie 交换约 50% 的新连接会处于非STATUS_HANDSHAKING状态直接跳过即可见上节说明。p.poll()每个已接受的PacketPeerDTLS都必须持续poll()来更新状态、驱动握手并处理收包poll()的文档明确要求频繁调用以保证连接正常工作。收发数据状态为STATUS_CONNECTED后通过继承自 PacketPeer 的get_available_packet_count()/get_packet()/put_packet()读写报文报文以PackedByteArray形式传递示例中用get_string_from_utf8()与to_utf8_buffer()做文本编解码。客户端实现完整示例DTLS 客户端由PacketPeerDTLS直接驱动无需DTLSServer。官方示例同样给出双语言版本。GDScript 版本client_node.gd# client_node.gd extends Node var dtls PacketPeerDTLS.new() var udp PacketPeerUDP.new() var connected false func _ready(): udp.connect_to_host(127.0.0.1, 4242) dtls.connect_to_peer(udp, false) # Use true in production for certificate validation! func _process(delta): dtls.poll() if dtls.get_status() PacketPeerDTLS.STATUS_CONNECTED: if !connected: # Try to contact server dtls.put_packet(The answer is... 42!.to_utf8_buffer()) while dtls.get_available_packet_count() 0: print(Connected: %s % dtls.get_packet().get_string_from_utf8()) connected trueC# 版本ClientNode.cs// ClientNode.cs using Godot; using System.Text; public partial class ClientNode : Node { private PacketPeerDtls _dtls new PacketPeerDtls(); private PacketPeerUdp _udp new PacketPeerUdp(); private bool _connected false; public override void _Ready() { _udp.ConnectToHost(127.0.0.1, 4242); _dtls.ConnectToPeer(_udp, validateCerts: false); // Use true in production for certificate validation! } public override void _Process(double delta) { _dtls.Poll(); if (_dtls.GetStatus() PacketPeerDtls.Status.Connected) { if (!_connected) { // Try to contact server _dtls.PutPacket(The Answer Is..42!.ToUtf8Buffer()); } while (_dtls.GetAvailablePacketCount() 0) { GD.Print($Connected: {_dtls.GetPacket().GetStringFromUtf8()}); _connected true; } } } }客户端关键点udp.connect_to_host(127.0.0.1, 4242)UDP 本质是无连接的此方法只是把 peer 定向到目标地址/端口之后来自其他地址的报文会被丢弃外出报文固定发往该地址且不再允许调用set_dest_address()。它不会真正向远端发送任何数据首次通信靠后面put_packet()完成。dtls.connect_to_peer(udp, false)PacketPeerDTLS.connect_to_peer(packet_peer, hostname, client_options null)的完整签名中第二个参数是用于校验证书的hostname域名第三个参数是client_optionsTLSOptions。示例中的false对应 GDScript 重载中的证书校验开关C# 中写作validateCerts: false仅用于本地开发生产环境必须开启证书校验。若要精细控制信任链与域名校验应改用TLSOptions.client(trusted_chain, common_name_override)或仅测试用TLSOptions.client_unsafe(trusted_chain)显式传入。状态轮询客户端同样每帧poll()直到get_status()变为STATUS_CONNECTED后才发送业务报文。示例用一个connected标志保证只发送一次打招呼消息避免重复触发。方法参考setup 与 take_connectionDTLSServer 总共只有两个方法见 class_dtlsserver.rst 的方法表返回类型方法签名说明Errorsetup(server_options: TLSOptions)使用给定的server_options配置 DTLS 服务器见TLSOptions.server()PacketPeerDTLStake_connection(udp_peer: PacketPeerUDP)对已连接的udp_peer尝试发起 DTLS 握手udp_peer必须已连接见PacketPeerUDP.connect_to_host()setup()的返回值是GlobalScope.Error可据此判断配置是否成功例如证书/密钥格式非法时返回错误码。take_connection()的注意事项上文已述必须检查返回的 PacketPeerDTLS 状态是否为STATUS_HANDSHAKING因为 cookie 交换导致约 50% 的新连接无效。配套类的底层细节PacketPeerUDPDTLS 的传输底座DTLS 始终运行在 UDP 之上因此 PacketPeerUDP 是整条链路的基础。常用方法一览bind(port, bind_address *, recv_buf_size 65536)绑定本地端口以便收包*绑定全部地址IPv4 IPv60.0.0.0/::限定 IP 类型指定具体 IP 则只绑定对应接口。connect_to_host(host, port)把 peer 定向到远端示例客户端的用法。set_dest_address(host, port)设置发送目标hostname 会经 DNS 解析。wait()阻塞等待一个包到达一旦调用无法中断可让对方发送death pill包来解除阻塞。get_packet_ip()/get_packet_port()获取最近收到报文的远端 IP/端口。文档特别提醒UDP 的连接并不能抵御 IP 欺骗等恶意攻击传输敏感信息时应使用 TLS/DTLS 这类加密手段——这正是 DTLSServer 存在的意义。UDPServer接纳新客户端UDPServer 提供listen(port, bind_address *)、poll()、is_connection_available()、take_connection()、stop()等 API。其中属性max_pending_connections 16定义了 poll 期间最多可积累的 pending connection 数量超出的新连接会被自动丢弃设为0可彻底拒绝新连接例如所有玩家都已进场时。PacketPeerDTLS每个加密会话的句柄除状态枚举外PacketPeerDTLS 还提供connect_to_peer(packet_peer, hostname, client_options null)客户端发起 DTLS 握手。disconnect_from_peer()断开并终止 DTLS 会话。get_status()返回连接状态。poll()驱动握手与收包需高频调用。该文档还包含一条重要的安全警告当前 TLS 证书吊销与证书固定certificate pinning均不支持——只要证书在其他方面有效已被吊销的证书也会被接受。若对此有顾虑建议使用有效期较短的自动托管证书。TLSOptions服务器与客户端配置的统一抽象TLSOptions 抽象了StreamPeerTLS与PacketPeerDTLS的配置无法直接实例化只能通过三个静态工厂方法创建方法用途server(key: CryptoKey, certificate: X509Certificate)服务器配置证书需含完整链client(trusted_chain null, common_name_override )客户端配置校验证书及公共名FQDNtrusted_chain传null时使用系统默认 CA 列表client_unsafe(trusted_chain null)不安全客户端配置不校验公共名仅建议测试使用注意在 Web 平台上TLS 校验始终强制使用浏览器自身的 CA 列表属于安全特性上述选项在该平台不生效。证书准备服务端setup()需要一对私钥与 X.509 证书.key 与 .crt二者分别对应 CryptoKey 与 X509Certificate均可像普通 Resource 一样load()。证书获取方式参考官方教程 TLS/SSL 证书ssl_certificates.rst生产环境推荐从证书颁发机构如 Lets Encrypt申请正式证书客户端无需额外配置因为 Godot 已内置 Mozilla 证书包作为兜底也可在 Project Settings 中覆盖自定义证书包。开发环境可使用 Godot 内置的Crypto.generate_self_signed_certificate()生成自签名证书或使用 OpenSSL 生成密钥与证书。自签名证书需要让客户端信任该证书例如通过TLSOptions.client()指定自定义信任链。安全红线私钥只能放在服务器端绝不能让客户端持有否则证书安全将完全失效。完整接入清单与注意事项把整套方案落地时请逐项核对Android 导出必须在 Android 导出预设中启用INTERNET权限远程部署同理否则一切网络通信都会被系统拦截PacketPeerUDP 与 PacketPeerDTLS 文档均有此警告。生产环境证书校验客户端connect_to_peer时务必开启证书校验validateCerts: true/ 传入TLSOptions.client()并确认hostname与证书 CN/域名匹配证书域名不匹配会得到STATUS_ERROR_HOSTNAME_MISMATCH。Cookie 交换的假失败服务端接受新连接后约 50% 会因 cookie 交换而不处于STATUS_HANDSHAKING必须当作正常流程跳过。高频 poll服务端对每个PacketPeerDTLS以及UDPServer都要在每帧poll()否则握手与收包会停滞。证书吊销限制吊销列表与证书 pinning 暂不支持密钥泄露风险高时应使用短有效期自动托管证书。服务器端限额可用max_pending_connections控制待处理连接上限满员时设 0 拒绝新连接。DTLS 在 Godot 中的更多应用场景DTLS 不止服务于这套 UDP 封装。在 ENetConnection 中Godot 提供了自定义 ENet 扩展让基于 ENet 的可靠 UDP 协议也能叠加 DTLS 加密服务端在create_host_bound()后立即调用dtls_server_setup(server_options)客户端在connect_to_host()前调用dtls_client_setup(hostname, client_options null)并可通过refuse_new_connections(bool)让 DTLS 服务器自动丢弃新连接详见该类的 dtls_server_setup 与 dtls_client_setup 方法说明。此外浏览器端的 WebRTC 标准也依赖 DTLS 作为其底层安全传输见 webrtc.rst 的协议背景介绍。理解 DTLSServer 的握手与状态机有助于触类旁通地理解 Godot 中其他基于 DTLS 的安全通信链路。小结DTLSServer 是 Godot 在纯 UDP 之上提供加密能力的关键组件它配合 UDPServer 接收裸 UDP 连接再用 TLSOptions 配置的密钥与证书将每个 PacketPeerUDP 升级为加密的 PacketPeerDTLS最终以标准 PacketPeer 接口收发数据。抓住三个要点即可快速上手cookie 交换导致的约 50% 握手失败属正常现象、每个 DTLS peer 必须持续 poll、生产环境务必开启证书校验。希望本文提供的双语言完整示例与配套类深度解析能帮助你在项目中直接落地一套可运行的 DTLS 安全通信服务端。赞分享文档教程游戏开发【免费下载链接】godot-docsGodot Engine official documentation项目地址https://gitcode.com/GitHub_Trending/go/godot-docs点击查看免费下载相关推荐Uppy Companion 集成示例实战从仓库安装到服务端与浏览器端配置解析Uppy Companion 集成示例实战从仓库安装到服务端与浏览器端配置解析 examples/companion 是 Uppy 官方仓库中一个小而精的前端UI组件后端RIOT DTLS sock 实战指南基于 sock_dtls_t 构建 DTLS 客户端与服务端RIOT DTLS sock 实战指南基于 sock_dtls_t 构建 DTLS 客户端与服务端 本文以 RIOT 官方示例 examples/networ物联网嵌入式操作系统实时系统GGUF还是GPTQ还是MLX 4bitMiniCPM5-2B量化格式选型完整清单GGUF还是GPTQ还是MLX 4bitMiniCPM5 2B量化格式选型完整清单 MiniCPM5 2B 是 OpenBMB 开源的面向端侧、本地部署和资源人工智能大模型基础模型上一篇10分钟打造专业级终端dotfiles3240新手入门终极指南下一篇DS4Windows跨平台适配与性能优化的PS4手柄映射方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考