1.WireGuard 教程:使用 DNS-SD 进行 NAT-to-NAT 穿透
2.SystemUIå¦ä½è·å¾SIMå¡ç¸å
³çmcc/mncå¼
3.[3D游戏开发实践] Cocos Cyberpunk 源码解读-目录结构
WireGuard 教程:使用 DNS-SD 进行 NAT-to-NAT 穿透
原文链接: fuckcloudnative.io/post...
WireGuard 是漫游码漫由 Jason A. Donenfeld 等人创建的下一代开源 *** 协议,旨在解决许多困扰 IPSec/IKEv2、类源Open*** 或 L2TP 等其他 *** 协议的游制问题。 年 1 月 日,作软WireGuard 正式合并进入 Linux 5.6 内核主线。漫游码漫
利用 WireGuard 我们可以实现很多非常奇妙的类源京东抢购源码功能,比如跨公有云组建 Kubernetes 集群,游制本地直接访问公有云 Kubernetes 集群中的作软 Pod IP 和 Service IP,在家中没有公网 IP 的漫游码漫情况下直连家中的设备,等等。类源
如果你是游制第一次听说 WireGuard,建议你花点时间看看我之前写的作软 WireGuard 工作原理。然后可以参考下面两篇文章来快速上手:
如果遇到某些细节不太明白的漫游码漫,再去参考 WireGuard 配置详解。类源
本文将探讨 WireGuard 使用过程中遇到的游制一个重大难题:如何使两个位于 NAT 后面(且没有指定公网出口)的客户端之间直接建立连接。
WireGuard 不区分服务端和客户端,大家都是客户端,与自己连接的所有客户端都被称之为Peer。
1. IP 不固定的 Peer
WireGuard 的核心部分是 加密密钥路由(Cryptokey Routing),它的工作原理是将公钥和 IP 地址列表(AllowedIPs)关联起来。每一个网络接口都有一个私钥和一个 Peer 列表,种子转磁力源码每一个 Peer 都有一个公钥和 IP 地址列表。发送数据时,可以把 IP 地址列表看成路由表;接收数据时,可以把 IP 地址列表看成访问控制列表。
公钥和 IP 地址列表的关联组成了 Peer 的必要配置,从隧道验证的角度看,根本不需要 Peer 具备静态 IP 地址。理论上,如果 Peer 的 IP 地址不同时发生变化,WireGuard 是可以实现 IP 漫游的。
现在回到最初的问题:假设两个 Peer 都在 NAT 后面,且这个 NAT 不受我们控制,无法配置 UDP 端口转发,即无法指定公网出口,要想建立连接,不仅要动态发现 Peer 的 IP 地址,还要发现 Peer 的端口。
找了一圈下来,现有的工具根本无法实现这个需求,本文将致力于不对 WireGuard 源码做任何改动的android 投屏源码情况下实现上述需求。
2. 中心辐射型网络拓扑
你可能会问我为什么不使用 中心辐射型(hub-and-spoke)网络拓扑?中心辐射型网络有一个 *** 网关,这个网关通常都有一个静态 IP 地址,其他所有的客户端都需要连接这个 *** 网关,再由网关将流量转发到其他的客户端。假设 Alice 和 Bob 都位于 NAT 后面,那么 Alice 和 Bob 都要和网关建立隧道,然后 Alice 和 Bob 之间就可以通过 *** 网关转发流量来实现相互通信。
其实这个方法是如今大家都在用的方法,已经没什么可说的了,缺点相当明显:
本文想探讨的是Alice 和 Bob 之间直接建立隧道,中心辐射型(hub-and-spoke)网络拓扑是无法做到的。
3. NAT 穿透
要想在Alice 和 Bob 之间直接建立一个 WireGuard 隧道,就需要它们能够穿过挡在它们面前的 NAT。由于 WireGuard 是通过 UDP 来相互通信的,所以理论上 UDP 打洞(UDP hole punching) 是最佳选择。
UDP 打洞(UDP hole punching)利用了这样一个事实:大多数 NAT 在将入站数据包与现有的连接进行匹配时都很宽松。这样就可以重复使用端口状态来打洞,因为 NAT 路由器不会限制只接收来自原始目的地址(信使服务器)的流量,其他客户端的流量也可以接收。
举个例子,chm文档的源码假设Alice 向新主机 Carol 发送一个 UDP 数据包,而 Bob 此时通过某种方法获取到了 Alice 的 NAT 在地址转换过程中使用的出站源 IP:Port,Bob 就可以向这个 IP:Port(2.2.2.2:) 发送 UDP 数据包来和 Alice 建立联系。
其实上面讨论的就是完全圆锥型 NAT(Full cone NAT),即一对一(one-to-one)NAT。它具有以下特点:
大部分的 NAT 都是这种 NAT,对于其他少数不常见的 NAT,这种打洞方法有一定的局限性,无法顺利使用。
4. STUN
回到上面的例子,UDP 打洞过程中有几个问题至关重要:
RFC 关于 STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)的详细描述中定义了一个协议回答了上面的一部分问题,这是一篇内容很长的 RFC,所以我将尽我所能对其进行总结。先提醒一下,STUN 并不能直接解决上面的问题,它只是个扳手,你还得拿他去打造一个称手的工具:
STUN 本身并不是 NAT 穿透问题的解决方案,它只是定义了一个机制,你可以用这个机制来组建实际的erlang项目源码分享解决方案。 — RFC
STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出自己的公网地址,查出自己位于哪种类型的 NAT 之后以及 NAT 为某一个本地端口所绑定的公网端口。这些信息被用来在两个同时处于 NAT 路由器之后的主机之间建立 UDP 通信。该协议由 RFC 定义。
STUN 是一个客户端-服务端协议,在上图的例子中,Alice 是客户端,Carol 是服务端。Alice 向 Carol 发送一个 STUN Binding 请求,当 Binding 请求通过 Alice 的 NAT 时,源 IP:Port 会被重写。当 Carol 收到 Binding 请求后,会将三层和四层的源 IP:Port 复制到 Binding 响应的有效载荷中,并将其发送给 Alice。Binding 响应通过 Alice 的 NAT 转发到内网的 Alice,此时的目标 IP:Port 被重写成了内网地址,但有效载荷保持不变。Alice 收到 Binding 响应后,就会意识到这个 Socket 的公网 IP:Port 是 2.2.2.2:。
然而,STUN 并不是一个完整的解决方案,它只是提供了这么一种机制,让应用程序获取到它的公网 IP:Port,但 STUN 并没有提供具体的方法来向相关方向发出信号。如果要重头编写一个具有 NAT 穿透功能的应用,肯定要利用 STUN 来实现。当然,明智的做法是不修改 WireGuard 的源码,最好是借鉴 STUN 的概念来实现。总之,不管如何,都需要一个拥有静态公网地址的主机来充当信使服务器。
5. NAT 穿透示例
早在 年 8 月...
SystemUIå¦ä½è·å¾SIMå¡ç¸å ³çmcc/mncå¼
SystemUIè·å¾SIMå¡ç¸å ³çmcc/mncå¼ï¼å两ç§æ åµè®¨è®ºè¿ä¸ªå¼æ¯åå¨å¨SIMå¡IMSIï¼å½é 移å¨ç¨æ·è¯å«ç International Mobile Subscriber Identification Numberï¼ä¸çåºå®å¼ï¼ä¸ä¼è¢«æ´æ¹ãæ以ä¸ä¸¤ç§éå¾å¯ä»¥åå¾ã
å¨TelephonyManagerä¸æå¦ä¸æ¹æ³ï¼
âââ
å¨æäºç¹æ®æ åµä¸ï¼æ¯å¦SIMå¡å¤äºPINç LOCKç¶ææ¶ï¼1.1ææå°çæ¹æ³æ¯åä¸å°çï¼è¿ä¸ªæ¶ååªè½éè¿SubscriptionInfoæ¥åã
注æï¼ç±äºè¿ä¸ªæ¹æ³åå°çmcc/mncå为intå¼ï¼æ¯å¦ä¸å½èéçââï¼åæmcc为ââï¼mnc为â1âï¼ä¸åºå®Stringå符串è¿è¡å¹é æ¯å¯¹çè¯ï¼éè¦å å°Stringæå为两é¨åååå«å¼ºè½¬æintååæå¯è¿è¡æ¯å¯¹ã
é漫游æ åµä¸ï¼æ³¨åç½ç»çmcc/mncå°±æ¯SIMå¡ä¸åå¨çãä½æ¯å¦æä½ çSIMå¡å¨å ¶ä»å½å®¶å¹¶æ²¡æ该è¿è¥åçåºç«ï¼åªè½éè¿æ¼«æ¸¸å°å ¶ä»è¿è¥åçç½ç»ä¸ç»´ææå¡æ¶ï¼æ³¨åç½ç»çmcc/mnc对åºçå°±æ¯è¯¥è¿è¥åçå¼ï¼ä¸SIMå¡æ å ³äºã
çæAndroid Telephonyæµç¨çæååºè¯¥é½ç¥éï¼CSãPSåç注åç¶æï¼æ¼«æ¸¸ç¶æï¼è¿è¥åååçæ¾ç¤ºï¼ç½ç»æ¨¡å¼çé½æ¯ç¨æ¨¡æ¿ç±»ServiceState.javaæ¥ä¿åçã
SystemUIä¸æä¸å°ç±»é½æ³¨åäºPhoneStateListenerè¿ä¸ªcallbackï¼ç¨æ¥æ¶å»å ³æ³¨è®¾å¤çä¸äºtelephonyç¸å ³ç¶æï¼å½ç½ç»æå¡ç¶ææååæ¶ï¼ä¼åè°å ¶onServiceStateChanged(ServiceState serviceState)æ¹æ³ï¼è¿æ ·æ们就å¯ä»¥ç´æ¥ä»ServiceStateéé¢åäºã
ä¸è¬æ¥è¯´ï¼voiceè¯é³ä¸å¡ådataæ°æ®ä¸å¡å¯¹åºçOperatorNumericæ¯ä¸æ ·çï¼æ以getOperatorNumeric()é»è®¤åäºvoiceçã
ç±äºè¯¥Intent action为MTKæ°å¢çï¼æ 以ä¸æ¹æ³ä»ç»å以MTKæºç 为åºç¡ã
ä¸é¢çæ¹æ³å¿ é¡»å¨voiceä¸dataå注åæåçåæä¸æè½è·å¾ï¼ä½æ¯å¨ä¸äºå¾ç¹æ®çç¯å¢ä¸ï¼æ¯å¦SIMå¡è½ç¶æ¼«æ¸¸ä¸äºæä¸ªå ¶ä»è¿è¥åçç½ç»ï¼ä½ç±äºä¸¤å®¶è¿è¥åä¹é´å¹¶æ²¡æåè®®ï¼å¯¼è´æ æ³æ³¨åä¸æå¡ï¼æ¤æ¶voiceådataåå¾çOperatorNumericå为空çã
å¨MTKæºç ä¸ï¼MtkServiceStateTrackerå¨å¤çPLMN Stringå³mcc/mncæ¶ï¼ä¼éè¿action为âTelephonyIntents.ACTION_LOCATED_PLMN_CHANGEDâç广æï¼æå®ä½ä¸ºextraåæ°ä¼ éåºå»ã
ç±æ¤å¯ç¥ï¼åªè¦å¨éè¦åçç±»ä¸ï¼æ³¨åä¸ä¸ªçå¬âACTION_LOCATED_PLMN_CHANGEDâçBroadcastReceiverå°±è¡äºï¼å¨è®¾å¤å¼æºä¹å便å¯ä»¥ç¬¬ä¸æ¶é´æ¿å°æ¼«æ¸¸ç½ç»çmcc/mncå¼ï¼å ·ä½å¦ä¸ï¼
[3D游戏开发实践] Cocos Cyberpunk 源码解读-目录结构
在深入解读Cocos Cyberpunk源码之前,首先,让我们打开scene-game-start场景,启动游戏预览,进入游戏场景。点击START按钮,游戏正式开始。漫游摄像机将带你漫游整个场景,再次点击START,可以进入游戏。
在电脑端按ESC键或手机端点击设置按钮,查看操作说明。接下来,让我们浏览Cocos Cyberpunk项目的目录结构。在左下角的Assets窗口中,我们可以看到项目文件的分层。
首先,animations目录中仅包含用于场景漫游的摄像机动画文件。LightFX目录存储了光照贴图,这些是光照烘焙系统自动生成的,无需手动修改。res目录是整个游戏资源的集中地,包括动画、特效、模型、shader、UI、音效等资源。
resources目录则存放动态加载的资源,当前内容较少,随着游戏的完善,资源将会增多。scene目录包含了环境反射探针文件,与场景文件名对应的文件夹存放反射贴图。scene-development目录则包含一些用于单元测试的开发场景。
scripts目录存放所有游戏逻辑脚本,而src目录可能包含项目开发过程中的测试文件。test目录同样是用于测试的,存放的文件与项目无关。scene目录则是游戏主场景,而scene-game-start则为游戏启动场景,进行UI逻辑初始化,并加载游戏主场景。
自定义管线以编辑器扩展的形式存在,可将其移至项目中。管线对应自定义管线,通过在场景中新建节点并添加pipeline/graph/pipeline-graph.ts组件来查看可视化管线图。实时探针相关组件在反射探针节点上挂载,提供实时更新功能。
反射探针节点上的ReflectionUtils脚本组件实现了实时更新探针的逻辑,适用于需要实时探针的项目。此外,Cocos Cyberpunk还实现了SphereProjection修正,使得反射更符合物体形状。
静态遮挡剔除机制在Cocos Cyberpunk中实现,通过将可见关系预存入空间格子,渲染时直接查表获得渲染列表,极大提升效率。这一部分主要在scene场景中的static-occlusion-culling结点中处理。
机型适配策略在Cocos Cyberpunk中实现,根据设备性能选择渲染效果,确保流畅帧率。处理了不同设备上的效果调整,包括性能开关策略、机型分档策略,主要在href-settings.ts、gpu.ts和gpu-mobiles.ts文件中实现。
游戏逻辑方面,Cocos Cyberpunk包含完整的TPS游戏逻辑,init节点包含了特效、UI、对象池等节点,挂载的init.ts脚本组件确保游戏逻辑在主场景加载后持续运行。接下来,我们将对游戏逻辑相关源码进行深入解读。