Unity 网络编程RPC层

初学者,自用笔记

基础类

// 通用网络消息
public class NetMessage
{
    public int MessageType;    // 消息类型ID
    public int RequestId;      // 请求ID
    public bool NeedResponse;  // 是否需要响应
    public byte[] Payload;     // 业务数据
}

消息处理器

职责抽象

// 消息处理器接口:按消息类型处理
public interface IMessageHandler
{
    int MessageType { get; }   // 当前处理哪种消息
    void Handle(NetMessage msg,int clientId); // 处理消息
}

// 处理器注册表接口
public interface IMessageHandlerRegistry
{
    void Register(IMessageHandler handler); // 注册处理器
    bool TryGetHandler(int messageType, out IMessageHandler handler); // 查找处理器
}

具体实现

// 处理器注册表实现
public class MessageHandlerRegistry : IMessageHandlerRegistry
{
    private readonly Dictionary<int, IMessageHandler> _handlers = new Dictionary<int, IMessageHandler>();

    // 注册处理器
    public void Register(IMessageHandler handler)
    {
        if (handler == null) return;
        _handlers[handler.MessageType] = handler;
    }

    // 查找处理器
    public bool TryGetHandler(int messageType, out IMessageHandler handler)
    {
        return _handlers.TryGetValue(messageType, out handler);
    }
}

// 示例:登录请求处理器
public class LoginRequestHandler : IMessageHandler
{
    public int MessageType => 1001;

    private readonly IRpcResponder _responder;

    public LoginRequestHandler(IRpcResponder responder)
    {
        _responder = responder;
    }

    public void Handle(NetMessage msg,int clientId)
    {
        // 处理登录逻辑
        var response = new NetMessage
        {
            MessageType = 1002,
            Payload = Encoding.UTF8.GetBytes("Login OK")
        };

        // 回包给请求方
        _responder.Reply(clientId, msg, response);
    }
}

服务端

响应器

// RPC响应器接口:负责把响应发回给请求方
public interface IRpcResponder
{
    void Reply(int clientId, NetMessage request, NetMessage response);
}

// RPC响应器实现
public class RpcResponder : IRpcResponder
{
    private readonly IServerSessionManager _sessionManager; // 会话管理器

    public RpcResponder(IServerSessionManager sessionManager)
    {
        _sessionManager = sessionManager;
    }

    // 给指定客户端回包
    public void Reply(int clientId, NetMessage request, NetMessage response)
    {
        if (request == null || response == null) return;

        // 保留原请求ID,方便客户端匹配回调
        response.RequestId = request.RequestId;
        response.NeedResponse = false;

        _sessionManager.SendTo(clientId, response);
    }
}

职责抽象

// 通用RPC服务端接口
public interface IRpcServer
{
    void Broadcast(NetMessage msg);        // 广播给所有客户端
    void SendTo(int clientId, NetMessage msg); // 发给指定客户端
    void RegisterHandler(IMessageHandler handler); // 注册处理器
    void Start(string ip, int port);       // 启动服务
    void Stop();                           // 停止服务
}

具体实现

// RPC服务端实现:负责广播、单播、消息分发
public class RpcServer : IRpcServer
{
    private readonly IServerSessionManager _sessionManager;   // 会话管理器
    private readonly IMessageHandlerRegistry _handlerRegistry; // 处理器注册表

    public RpcServer(
        IServerSessionManager sessionManager,
        IMessageHandlerRegistry handlerRegistry)
    {
        _sessionManager = sessionManager;
        _handlerRegistry = handlerRegistry;

        // 监听会话层收到的消息
        _sessionManager.OnMessageReceived += OnSessionMessageReceived;
    }

    // 启动服务
    public void Start(string ip, int port)
    {
        _sessionManager.Start(ip, port);
    }

    // 停止服务
    public void Stop()
    {
        _sessionManager.Stop();
    }

    // 注册消息处理器
    public void RegisterHandler(IMessageHandler handler)
    {
        _handlerRegistry.Register(handler);
    }

    // 广播消息给所有客户端
    public void Broadcast(NetMessage msg)
    {
        if (msg == null) return;
        msg.NeedResponse = false;
        _sessionManager.Broadcast(msg);
    }

    // 发送消息给指定客户端
    public void SendTo(int clientId, NetMessage msg)
    {
        if (msg == null) return;
        msg.NeedResponse = false;
        _sessionManager.SendTo(clientId, msg);
    }

    // 会话层收到消息后,交给处理器
    private void OnSessionMessageReceived(object obj, int clientId)
    {
        if (obj is not NetMessage msg) return;

        if (_handlerRegistry.TryGetHandler(msg.MessageType, out var handler))
        {
            handler.Handle(msg,clientId);
        }
    }
}

客户端

请求器

// 请求上下文:保存请求信息和回调
public class RpcRequestContext
{
    public int RequestId;                    // 请求ID
    public float SendTime;                   // 发送时间
    public float Timeout;                    // 超时时间
    public Action<NetMessage> Callback;      // 响应回调
}

// 请求管理器接口:管理请求、响应、超时
public interface IRpcRequestManager
{
    int NextRequestId(); // 获取新的请求ID
    void AddRequest(int requestId, float timeout, Action<NetMessage> callback); // 添加请求
    void OnResponse(NetMessage msg); // 收到响应
    void Tick(float now); // 超时检查
}

// 请求管理器实现
public class RpcRequestManager : IRpcRequestManager
{
    private readonly Dictionary<int, RpcRequestContext> _requests = new Dictionary<int, RpcRequestContext>();
    private int _nextId = 1;

    // 获取下一个请求ID
    public int NextRequestId()
    {
        return _nextId++;
    }

    // 添加请求
    public void AddRequest(int requestId, float timeout, Action<NetMessage> callback)
    {
        _requests[requestId] = new RpcRequestContext
        {
            RequestId = requestId,
            SendTime = Time.realtimeSinceStartup,
            Timeout = timeout,
            Callback = callback
        };
    }

    // 收到响应
    public void OnResponse(NetMessage msg)
    {
        if (msg == null) return;

        if (_requests.TryGetValue(msg.RequestId, out var ctx))
        {
            _requests.Remove(msg.RequestId);
            ctx.Callback?.Invoke(msg);
        }
    }

    // 检查超时
    public void Tick(float now)
    {
        var timeoutList = _requests
            .Where(kvp => now - kvp.Value.SendTime > kvp.Value.Timeout)
            .Select(kvp => kvp.Key)
            .ToList();

        foreach (var requestId in timeoutList)
        {
            _requests.Remove(requestId);
        }
    }
}

职责抽象

// 通用RPC客户端接口
public interface IRpcClient
{
    void Send(NetMessage msg); // 普通同步消息发送
    void SendRequest(NetMessage msg, float timeout, Action<NetMessage> callback); // 请求消息发送
    void RegisterHandler(IMessageHandler handler); // 注册处理器
    void Connect(string ip, int port); // 连接服务端
    void Disconnect(); // 断开连接
    event Action<bool> OnConnectStateChanged; // 连接状态变更
}

具体实现

// RPC客户端实现:负责同步消息、请求消息、回包和处理器分发
public class RpcClient : IRpcClient
{
    private readonly IClientNetworkSession _session;            // 会话层
    private readonly IMessageHandlerRegistry _handlerRegistry;   // 处理器注册表
    private readonly IRpcRequestManager _requestManager;        // 请求管理器

    public event Action<bool> OnConnectStateChanged;

    public RpcClient(
        IClientNetworkSession session,
        IMessageHandlerRegistry handlerRegistry,
        IRpcRequestManager requestManager)
    {
        _session = session;
        _handlerRegistry = handlerRegistry;
        _requestManager = requestManager;

        // 会话层连接状态转发
        _session.OnConnected += () => OnConnectStateChanged?.Invoke(true);
        _session.OnDisconnected += () => OnConnectStateChanged?.Invoke(false);

        // 会话层收到消息后进入 RPC 层
        _session.OnMessageReceived += OnSessionMessageReceived;
    }

    // 连接服务端
    public void Connect(string ip, int port)
    {
        _session.Connect(ip, port);
    }

    // 断开连接
    public void Disconnect()
    {
        _session.Close();
    }

    // 注册业务消息处理器
    public void RegisterHandler(IMessageHandler handler)
    {
        _handlerRegistry.Register(handler);
    }

    // 普通同步消息发送
    public void Send(NetMessage msg)
    {
        if (msg == null) return;

        msg.NeedResponse = false;
        _session.Send(msg);
    }

    // 请求消息发送:带超时和回调
    public void SendRequest(NetMessage msg, float timeout, Action<NetMessage> callback)
    {
        if (msg == null) return;

        int requestId = _requestManager.NextRequestId();
        msg.RequestId = requestId;
        msg.NeedResponse = true;

        _requestManager.AddRequest(requestId, timeout, callback);
        _session.Send(msg);
    }

    // 会话层收到消息后统一进入这里
    private void OnSessionMessageReceived(object obj)
    {
        if (obj is not NetMessage msg) return;

        // 如果是响应消息,交给请求管理器
        if (msg.RequestId > 0 && !msg.NeedResponse)
        {
            _requestManager.OnResponse(msg);
            return;
        }

        // 如果是普通业务消息,按类型分发给处理器
        if (_handlerRegistry.TryGetHandler(msg.MessageType, out var handler))
        {
            handler.Handle(msg);
        }
    }

    // 每帧更新:检查请求超时
    public void Tick(float deltaTime)
    {
        _requestManager.Tick(Time.realtimeSinceStartup);
    }
}
全部评论

相关推荐

02-26 13:56
已编辑
重庆财经学院 Java
King987:你有实习经历,但是写的也太简单了,这肯定是不行的,你主要要包装实习经历这一块,看我的作品,你自己包装一下吧,或者发我,我给你出一期作品
点赞 评论 收藏
分享
Gardenia06...:刚开始学是这样的,可以看看左神和灵神都讲的不错
点赞 评论 收藏
分享
评论
点赞
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务