Files
netease-modsdk-wiki/docs/mconline/90-知识库获奖教程/4-SDK实用技巧/0-更高效的进行双端通信.md
boybook 760c2dd9ad 2.6
2025-12-01 20:59:16 +08:00

132 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 更高效的进行双端通信
> 本篇教程获得第一期知识库必看教程奖。
>
> 获奖作者:红石公司。
## 前言
在我的世界模组和网络服的开发过程中,经常需要进行 服务端与客户端 ,或其他系统之间的通信。
一般的我们使用Notify与Broadcast事件进行通信。 但是每次新增一个通信事件都需要使用ListenForEvent接口进行监听。
大部分开发者都将ListenForEvent的调用写在`__init__`里,这就导致无法热更新,需要退出游戏重新进入,十分影响开发效率。
**学习本教程你将掌握:**
- 如何进行通信事件的热更新。
- 如何将调用远程系统变得像调用自身一样方便。
**效果图示:**
- 在服务端发送消息时,向客户端发送事件 并获取返回值。
![img](./images/0_0.png)
![img](./images/0_1.png)
![img](./images/0_2.png)
**学习本教程的前提:**
- 熟悉Python并进行过模组开发。
- 掌握通信事件`NotifyToServer``NotifyToClient``BroadcastToAllClient`的用法。
## 原理分析解释
根据效果图示可以看到,服务端直接调用了一个未经创建的方法名,这个方法名对应了客户端的方法。在客户端通过某种方式获取到此方法并成功执行。
客户端的return再次返回到服务端并触发回调函数。
由此可得三个技术点:
1. 使用未创建的方法。
2. 动态获取实例方法。
3. 回调的实现。
### 使用未创建的方法
通过重写`__getattr__`方法可以截获正在调用的方法名。
![img](./images/0_3.png)
在此返回一个其他方法,将不会引起报错,我将其称为”万能方法“。并且可以将截获的方法名保存下来,在”万能方法“真正被调用时,可以获得:
1. 刚才保存的方法名。
2. 传入的参数。
这两个集齐了我们通信函数所需的全部参数。可以正常进行通信。如下图所示:
![img](./images/0_4.png)
### 动态获取方法
python可以通过内置函数 getattr(obj, attr_name) 获取某个对象的属性值,返回值是属性本身,可以直接使用。
![img](./images/0_5.png)
由于调用不存在的方法名会引起报错,所以这里的`getattr`在实际使用时要放在try语句内。
如此,在双端建立的固定通信函数用于发送与接收事件,参数里传入`attr_name,` 在远程端接收到事件后,`getattr`解析`attr_name`为本地方法,即可直接使用。
### 回调的实现
回调本质上也是一次通信,不同的是,不是通过`getattr`方法名获取方法对象,而是一个本身就存在的函数或方法对象,比如一个嵌套函数里的子函数,这通过`getattr`是抓不到的。
所以我们需要检测一个关键字,我这里选用`back`
为了远程端返回回调后,本地端能够顺利找到回调函数对象,我们使用`uuid`模块的`uuid.uuid1().hex`获取一个回调id保存在本地端同时加入通信参数里。
远程端收到事件并执行后检测到参数里有一个back字段就将 执行结果 与 回调id重新通过通信事件发回本地端。
本地端由回调id从刚才的缓存里取出函数对象并执行。到此一个回调过程完成。但是禁止套娃
以上就是通信的热更与直接执行、接受回调 所涉及到的技术难点。
示例代码在这里:[下载地址](https://share.weiyun.com/wGawl7J1)。
示例结果图示:
![img](./images/0_6.png)
![img](./images/0_7.png)
![img](./images/0_8.png)
demo只简单展示了客户端与服务端的双向通信仅作为功能预览不具备实用性。还需要各位开发者根据自己的实际情况以及编程习惯开发自己的通信系统。
## 拓展
研究透彻后,可以尝试解决以下拓展问题:
- 服务端向所有客户端发送事件,该如何修改代码。
- 客户端或服务端,向本端的其他系统发送事件,该如何修改代码。
- UI或其他自定义逻辑类中如何不通过 服务端/客户端 中继,直接使用通信。
解决上述问题后,你的通信系统将趋于完善,这将大大加快你的开发进度,提升你的开发效率。(本工作室《我的世界工具盒子》模组,就是采用此方式来应对高频的通信需求。)
本人是编程新手,也是开发新手,教程如有什么纰漏,表述不当,还请大家指出改进。 若有哪里不明白的地方,可以在评论区提问,我会及时解答的。