TinyRPC
为 Unity 准备的使用 TCP + JsonUtility + Task 实现的极简的现代网络框架,支持 RPC 和常规消息收发。使用 upm 管理,对项目文件 0 侵入;A minimalistic modern networking framework prepared for Unity using TCP, JsonUtility, and Task to implement support for RPC and regular message sending/receiving. Managed via UPM with zero intrusion into the project files.
Install / Use
/learn @Bian-Sh/TinyRPCREADME
本说明有配图,请确保你的网络畅通,图文模式下阅读更佳。
<a id="chinese">English</a>
TinyRPC
TinyRPC 是一个为 Unity 引擎准备的,没有第三方插件依赖、仅使用 TCP + JsonUtility + Task实现的极简 RPC 网络框架,支持 RPC/常规 消息分发。它的目标是提供一个轻量级、易于使用的网络通信解决方案。
这个网络框架很多地方学习、参考了 ET ,在此表示感谢。
基于 TinyRPC 的示例项目 :unity-drones-multiplayer-tinyrpc
图片借用 unity-drones-multiplayer的配图, 图示内容不代表最终效果!

特性
-
支持局域网网络发现,提供了一个简单的测试用例,自动发现并连接到局域网内的服务器。
-
支持
async await异步逻辑同步写的语法糖,让你的代码更加简洁优雅且易读。 -
支持客户端和服务器互发 RPC 请求。
-
支持常规网络消息的收发
-
支持基于 TCP 建立连接之上的网络通信,完整的生命周期管理,断线即刻感知。
-
2 种消息处理的注册方案:监听模式 、Attribute 标注模式
功能
消息的发送
-
使用
Send(message)发送普通网络消息 -
使用
var response = await Call(request)发送 RPC 请求并等待响应
观察者模式注册的消息处理器
-
使用
UnityEngine.Component.AddNetworkSignal<Session,T>()注册一个普通的网络处理器 -
使用
UnityEngine.Component.AddNetworkSignal<Session,TRequest,TResponse>()注册一个 RPC 处理器
通过反射自动注册消息处理器
- 使用
[MessageHandlerProviderAttribute]标记一个消息处理器容器(类型) - 使用
[MessageHandlerAttribute(MessageType.Normal)]标记一个消息处理器 - 使用
[MessageHandlerAttribute(MessageType.RPC)]标记一个 RPC 消息处理器
消息类一键生成
使用基于 proto3 精简版语法的 .proto 文件,可以一键生成消息类。如果存在多个 .proto 文件则会将消息生成在以 .proto 文件名命名的文件夹中。
支持将生成的消息存在 Assets、Project 同级以及 Packages 文件夹中。他们的优越性在于生成在 Packages 文件夹中不会对用户工程目录有任何侵入性;存在 Project 同级目录将最大化的实现消息文件在多个工程中的复用(本项目架构情形)。

运行时参数配置界面
提供了一个可以编辑器下修改、运行时生效的配置界面,可以配置日志过滤器;心跳间隔和重试次数;同时也会自动记录消息处理器所在的程序集信息

RPC 原理
-
TinyRPC 使用
System.Threading.Tasks命名空间下的TaskCompletionSource来实现 RPC 的异步等待。 -
使用
System.Threading.Tasks命名空间下的CancellationTokenSource.CancelAfter(delay)来实现 RPC 的超时控制。 -
使用对
UnityEngine.Component新增扩展方法的方式实现在 MonoBehaviour 实例中像使用本地函数一样注册消息处理器 -
使用
System.Reflection命名空间下的MethodInfo配合Delegate.CreateDelegate(typeof(Action<Session, T>), method)实现对MessageHandlerAttribute(MessageType.Normal)标注的常规消息处理器的自动注册 -
使用
System.Reflection命名空间下的MethodInfo配合Delegate.CreateDelegate(typeof(Func<Session, TRequest, TResponse, Task>), method)实现对MessageHandlerAttribute(MessageType.RPC)标注的 RPC 消息处理器的自动注册 -
使用
MessageWrapper记录消息的类型信息及其 Json 数据来实现通过JsonUtility也能对多继承消息的序列化/反序列化
安装
通过 git URL 安装
-
点击
Window->Package Manager打开 Package Manager 窗口 -
将
https://github.com/Bian-Sh/TinyRPC.git/?path=Common/TinyRPC粘贴到 Package Manager 中(大小写敏感) -
想要支持从 git URL 安装,需要使用 Unity 2019.3.4f1 或更高版本
-
在中国使用 git URL 安装的成功率较低,请自行选择其他安装方式。

快速开始
-
克隆此仓库到你的本地机器上。
-
在 Unity 编辑器中分别打开 Client 和 Server 项目
-
先运行 Server ,此时会自动创建服务器
-
再运行 Client , 点击 Play 后在 Game 窗口可以连接/断开服务器,通过 SendRPC 测试 RPC 会话。
-
本项目使用 Unity 2021.3.11f2 开发 ,请使用此版本或者更高阶版本

- 你也可以把 TinyRPC 提供的 Server 示例 打包成 Dedicated Server 部署在 Dedicated Server 支持的系统或平台上!


登录、消息发送
在 Unity 客户端中,我们使用了以下关键 API:
client.ConnectAsync(): 这个方法用于连接到服务器。client.Send(message): 这个方法用于发送一个普通消息。await client.Call<TestRPCResponse>(request): 这个方法用于发送一个 RPC 请求并等待响应。
登录逻辑
下面是 TinyRPC 连接服务器逻辑
也模拟了网络不好情况下的登录表现,展示了如何通过 async 异步对登录流程的优雅控制。
private async void StartConnectAsync()
{
connect.interactable = false;
//模拟网络延迟情况下的登录
//1. 显示登录中...
var tcs = new CancellationTokenSource();
_ = TextLoadingEffectAsync(tcs);
//2. 模拟一个延迟完成的登录效果
var delay = Task.Delay(3000);
var task = client.ConnectAsync();
await Task.WhenAll(delay, task);
//3. 取消登录中...的显示
tcs.Cancel();
//4. 转换 connect 字样为 disconnect
connect.GetComponentInChildren<Text>().text = "Disconnect";
connect.interactable = true;
}
这段逻辑中,我使用 Task.WhenAll + Task.Delay 实现了一个长时间的登录效果,这样文本组件就有足够时间展示 Connect... 动画了,当登录完成,就将文本改为 Disconnect,方便下个回合的交互。
当然,你还可以对这段逻辑 Try Catch,处理登录失败的情况,这里我就不誊写啦,更多交互细节请运行示例项目体验。
RPC 消息发送
下面是 TinyRPC 发送 RPC 并等待回应的逻辑,同样,得益于 RPC 的使用,与服务器的对话再也不需要调用 监听者模式这种割裂的交互方式了(TinyRPC也支持监听模式,毕竟还有常规消息要处理嘛)
public async void SendRPCAsync()
{
if (client != null && client.IsConnected)
{
var request = new TestRPCRequest();
request.name = "request from tinyrpc client";
var response = await client.Call<TestRPCResponse>(request);
}
}
这段逻辑中,我先构建了一个请求,并告知服务请求的信息,接着等待服务器返回的数据。
常规消息发送
下面是 Tiny RPC 发送常规消息的逻辑,构建一个 Normal 消息,调用 Send 就好啦。
private void SendNormalMessage()
{
if (client != null && client.IsConnected)
{
var message = new TestMessage
{
message = "normal message from tinyrpc client",
age = 999
};
client.Send(message);
}
}
消息处理
在服务器端,我们使用了消息处理器来处理接收到的各类消息:Normal 消息、RPC 消息、Ping 消息。
当然,在客户端也支持通过注册消息处理器来处理 Normal 消息、RPC 消息 (Ping 消息除外)进而实现用户业务逻辑的展开。
Ping 消息处理器
Ping 消息是一个内置的自响应消息,交由系统自己处理,用户无需关注
#region Ping Message Handler
private static async Task OnPingRecevied(Session session, Ping request, Ping response)
{
response.Id = request.Id;
response.time = ServerTime;
await Task.CompletedTask();
}
#endregion
RPC 消息处理器
- 下面的示例脚本演示如何通过
MessageHandlerProviderAttribute、MessageHandlerAttribute声明 RPC 消息处理器
[MessageHandlerProvider]
class Foo
{
[MessageHandler(MessageType.RPC)]
private static async Task RPCMessageHandler(Session session, TestRPCRequest request, TestRPCResponse response)
{
Debug.Log($"{nameof(TestServer)}: Receive {session} request {request}");
await Task.Delay(1000);
response.name = "response from tinyrpc server !";
}
}
这个消息处理器收到 RPC 请求后,间隔了一秒钟,然后向请求端发出响应信息: “response from tinyrpc server ”。
- 下面示例脚本中演示如何使用
UnityEngine.Component.AddNetworkSignal<Session,TRequest,TResponse>()注册/注销 RPC 消息处理器
using System.Threading.Tasks;
using UnityEngine;
using zFramework.TinyRPC;
using zFramework.TinyRPC.Generated;
public class Foo : MonoBehaviour
{
private void OnEnable()=>this.AddNetworkSignal<TestRPCRequest, TestRPCResponse>(RPCMessageHandler);
private void OnDisable()=>this.RemoveNetworkSignal<TestRPCRequest, TestRPCResponse>(RPCMessageHandler);
private static async Task RPCMessageHandler(Session session, TestRPCRequest request, TestRPCResponse response)
{
await Task.Delay(500);
response.name = $"response from tinyrpc {(session.IsServerSide ? "SERVER" : "CLIENT")} !";
}
}
普通消息处理器
- 下面的示例脚本中演示如何使用
MessageHandlerProviderAttribute、MessageHandlerAttribute声明普通消息处理器
[MessageHandlerProvider]
class Foo
{
[MessageHandler(MessageType.Normal)]
private static void NormalMessageHandler(Session session, TestMessage message)
{
Debug.Log($"{nameof(TestServer)}: Receive {session} message {message}");
}
}
这个消息处理器收到普通消息后,直接 log 输出到屏幕。
- 下面示例脚本中演示如何使用
UnityEngine.Component.AddNetworkSignal<Session,T>()注册普通消息处理器
using UnityEngine;
using zFramework.TinyRPC;
using zFramework.TinyRPC.Generated;
public class Foo: MonoBehaviour
{
private void OnEnable()=>this.AddNetworkSignal<TestMessage>(OnTestMessageReceived);
private void OnDisable()=>this.RemoveNetworkSignal<TestMessage>(OnTestMessageReceived);
private void OnTestMessageReceived(Session session, TestMessage message)
{
Debug.Log($"获取到{(session.IsServerSide ? "客户端" : "服务器")} {session} 的消息, message = {message}");
}
}
框架架构
下面是 TinyRPC 的文件系统树,点击可以看到完整网络架构
<details> <summary> 点我 ^_^</summary><root>
|
+---Editor
| |
| +---Analyzer
| | MessageHandlerPostprocessor.cs
| |
| +---Async
| | TaskDriver.cs
| | UpmRequestAwaiter.cs
| | UpmRequestExtension.cs
| |
| +---CodeGen
| | ProtoContentProcessor.cs
| | TinyProtoHandler.cs
| |
| +---Data
| | ScriptInfo.cs
| | ScriptType.cs
| |
| +---GUI
| | EditorSettingsLayout.cs
| | RuntimeSettingsLayout.cs
| | TinyRpcEditorWindow.cs
| |
| \---Settings
| EditorSettingWatcher.cs
| ScriptableSingleton.cs
| TinyRpcEditorSettings.cs
|
\---Runtime
|
+---Data
| IReusable.cs
| MessageType.cs
| MessageWrapper.cs
| ObjectPool.cs
| RpcInfo.cs
| SerializeHelper.cs
| TinyRpcSettings.cs
|
+---Discovery
| DiscoveryClient.cs
| DiscoveryServer.cs
|
+---Exception
| InvalidSessionException.cs
| RpcResponseException.cs
| RpcTimeoutException.cs
|
+---Handler
| |
| +---Attribute
| | MessageHandlerAttribute.cs
| | MessageHandlerProviderAttribute.cs
| |
| +---Base
| | NormalMessageHandler.cs
| | RpcMessageHandler.cs
| |
| +---Extension
| | MessageHandlerEx.cs
| |
| \---Interface
| INormalMessageHandler.cs
| IRpcMessageHandler.cs
|
+---Internal
| Manager.cs
| Session.cs
| TinyClient.cs
| TinyServer.cs
|
\---Message
|
+---Attribute
| ResponseTypeAttribute.cs
|
+---Base
| Message.cs
| Ping.cs
| Request.cs
| Response.cs
|
\---Interface
IMessage.cs
IRequest.cs
IResponse.cs
IRpcMessage.cs
Related Skills
openhue
351.2kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
351.2kElevenLabs text-to-speech with mac-style say UX.
weather
351.2kGet current weather and forecasts via wttr.in or Open-Meteo
casdoor
13.3kAn open-source AI-first Identity and Access Management (IAM) /AI MCP & agent gateway and auth server with web UI supporting OpenClaw, MCP, OAuth, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA, Face ID, Google Workspace, Azure AD
