Unity 网络 之 Networking 实现简单的网络服务器和客户端通讯功能封装(可监听多个客户端)

 

 

Unity 网络 之 Networking 实现简单的网络服务器和客户端通讯功能封装(可监听多个客户端)

 

目录

Unity 网络 之 Networking 实现简单的网络服务器和客户端通讯功能封装(可监听多个客户端)

一、简单介绍

二、实现原理

三、注意事项

四、效果预览

五、实现步骤

六、关键代码

七、参考工程


 

一、简单介绍

Unity 中网络通讯知识的整理。

本节介绍,在Unity中用 NetworkServer、NetworkClient 两个封装一个通用功能的类(包括建立连接,断开连接,发送不同类型数据,处理不同类型数据,注册处理数据的委托) 和 NetworkMessage (这里可以定义自己的消息类型,和重写消息数据结构)来解析数据信息,实现一个简单的网络通讯 demo。

因为是简单的封装,基本通讯可以满足使用,仅供参考,若有不对,请指出哈,谢谢。
 

二、实现原理

1、NetworkServer 构建相关服务器的封装类,例如 服务器监听 NetworkServer.Listen(),断开服务器所有连接NetworkServer.DisconnectAll(),关闭服务器NetworkServer.Shutdown(),服务器发送数据给所有客户端NetworkServer.SendToAll(),服务器取消注册事件 NetworkServer.UnregisterHandler(),服务器注册事件 NetworkServer.RegisterHandler()

2、NetworkClient 构建相关服务器的封装类,例如 客户端连接服务器 NetworkClient.Connect(),断开与服务器连接NetworkClient.Disconnect(),客户端发送数据给服务器NetworkClient.Send(),客户端取消注册事件 NetworkClient.UnregisterHandler(),客户端注册事件 NetworkClient.RegisterHandler()

3、继承 MessageBase 来定义自己的数据消息结构

 

三、注意事项

1、除了封装 NetworkServer、NetworkClient 两个类,还封装了一个统一管理 NetworkServer、NetworkClient  的管理类

NetManager 来实现来着的公有接口,外界只要调用 NetManager 的即可,内部会自动判断是否是构建服务器还是客户端

 

四、效果预览

 

五、实现步骤

1、打开Unity,新建工程

 

2、在场景中,搭建 UI,布局如下

 

3、新建几个脚本,完成 Networking 服务端、客户端的构建,以及 自定义数据类型事件,并有一个测试脚本,测试 Networking 的封装功能

 

4、把测试脚本和 NetManager 挂载到场景中个,并对应赋值

 

5、给 按钮添加测试脚本对应功能的接口函数

 

6、打包,运行多个客户端,即可完成数据通讯

 

六、关键代码

1、NetManager

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NetManager : MonoBehaviour
{

    private bool isServer = false;

    private NetServer server;
    private NetClient client;

    private string m_ip;
    private int m_port;

    Action addListenerEvent;

    /// <summary>
    /// 创建局域网通讯
    /// </summary>
    /// <param name="ip"></param>
    /// <param name="port"></param>
    public void SetUp(string ip, int port, Action action) {
        m_ip = ip;
        m_port = port;

        addListenerEvent = action;

        SetupClient();

    }

    /// <summary>
    /// 断开局域网通讯
    /// </summary>
    public void Shutdown(){
        if (server != null) {
            server.ShutdownServer();
        }

        if (client != null)
        {
            client.ShutdownClient();
        }
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="message"></param>
    public void SendUserMessage(string message) {
        if (server != null)
        {
            server.ServerSendUserMessage(message);
        }

        if (client != null)
        {
            client.ClientSendUserMessage(message);
        }
    }


    public void SetupEvent(Action<string> action) {
        if (action != null)
        {

            if (server != null)
            {
                server.SetupEvent += action;
            }

            if (client != null)
            {
                Debug.Log(" client.SetupEvent += action; ");
                client.SetupEvent += action;
            }

        }
    }

    public void ShutdownEvent(Action<string> action)
    {
        if (action != null)
        {

            if (server != null)
            {
                server.ShutdownEvent += action;
            }

            if (client != null)
            {
                client.ShutdownEvent += action;
            }

        }
    }

    public void OneTerminalConnectedEvent(Action<string> action)
    {
        if (action != null)
        {

            if (server != null)
            {
                server.OneTerminalConnectedEvent += action;
            }

            if (client != null)
            {
                client.OneTerminalConnectedEvent += action;
            }

        }
    }

    public void OneTerminalDisconnectedEvent(Action<string> action)
    {
        if (action != null)
        {

            if (server != null)
            {
                server.OneTerminalDisconnectedEvent += action;
            }

            if (client != null)
            {
                client.OneTerminalDisconnectedEvent += action;
            }

        }
    }

    public void NetErrorEvent(Action<string> action)
    {
        if (action != null)
        {

            if (server != null)
            {
                server.NetErrorEvent += action;
            }

            if (client != null)
            {
                client.NetErrorEvent += action;
            }

        }
    }

    public void RecieiveUserMessageHandlerEvent(Action<string> action)
    {
        if (action != null)
        {

            if (server != null)
            {
                server.RecieiveUserMessageHandlerEvent += action;
            }

            if (client != null)
            {
                client.RecieiveUserMessageHandlerEvent += action;
            }

        }
    }



    #region  私有方法处理

    void SetupClient()
    {
        if (client == null)
        {
            client = new NetClient(m_ip, m_port);
    
        }

        if (addListenerEvent != null)
        {
            addListenerEvent();
        }
        else {
            Debug.Log("addListenerEvent is null");
        }


        client.SetupClient();

        

        // 后期看是否可以改为 InvokeRepeating() 几次后,没有再去创建服务
        Invoke("ToSetupServer", 1.0f);

    }

    void ToSetupServer()
    {
        // 没有连接服务器,创建服务器
        if (client.GetClientConnectState() == false)
        {
            // 先处理Client,断开处理
            client.Disconnect();
            client = null;

            SetupServer();
        }

    }


    void SetupServer()
    {
        if (server == null)
        {
            server = new NetServer(m_port);

            if (addListenerEvent != null)
            {
                addListenerEvent();
            }
        }

        // 为服务端
        isServer = true;

        server.SetupServer();
    }

    /// <summary>
    /// 监听客户端是否连接服务器
    /// </summary>
    /// <returns></returns>
    IEnumerator ClientConnectListener() {
        while (client.GetClientConnectState()==false)
        {
            yield return new WaitForSeconds(1.0f);
        }
    }

    #endregion


}

 

2、NetServer

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class NetServer 
{


    public Action<string> SetupEvent;
    public Action<string> ShutdownEvent;
    public Action<string> OneTerminalConnectedEvent;
    public Action<string> OneTerminalDisconnectedEvent;
    public Action<string> NetErrorEvent;
    public Action<string> RecieiveUserMessageHandlerEvent;

    int m_port;

    public NetServer(int port) {
        m_port = port;
    }


    /// <summary>
    /// 建立服务器
    /// </summary>
    public void SetupServer()
    {
        if (!NetworkServer.active)
        {
            Debug.Log("setup server");
            ServerRegisterHandler();
            NetworkServer.Listen(m_port);

            if (NetworkServer.active)
            {
                Debug.Log("Server setup ok.");
                if (SetupEvent != null) {
                    SetupEvent("Server setup ok.");
                }
            }
        }
    }

    /// <summary>
    /// 停止服务器端
    /// </summary>
    public void ShutdownServer()
    {
        if (NetworkServer.active)
        {
            ServerUnregisterHandler();
            NetworkServer.DisconnectAll();
            NetworkServer.Shutdown();

            if (!NetworkServer.active)
            {
                Debug.Log("shut down server");
                if (ShutdownEvent != null)
                {
                    ShutdownEvent("shut down server");
                }

            }
        }
    }


    /// <summary>
    /// 服务器端向所有客户端发送信息
    /// </summary>
    public void ServerSendUserMessage(string message)
    {
        if (NetworkServer.active)
        {
            UserMessage um = new UserMessage();
            um.message = message;
            if (NetworkServer.SendToAll(MyMsgType.UserMessage, um))
            {
                Debug.Log("Server send:" + message);

               
            }
        }
    }



    /// <summary>
    /// 服务器端注册事件
    /// </summary>
    private void ServerRegisterHandler()
    {
        NetworkServer.RegisterHandler(MsgType.Connect, OnServerConnected);
        NetworkServer.RegisterHandler(MsgType.Disconnect, OnServerDisconnected);
        NetworkServer.RegisterHandler(MsgType.Error, OnServerError);
        NetworkServer.RegisterHandler(MyMsgType.UserMessage, ServerRecieiveUserMessageHandler);

    }


    /// <summary>
    /// 服务器端注销事件
    /// </summary>
    private void ServerUnregisterHandler()
    {
        NetworkServer.UnregisterHandler(MsgType.Connect);
        NetworkServer.UnregisterHandler(MsgType.Disconnect);
        NetworkServer.UnregisterHandler(MsgType.Error);
        NetworkServer.UnregisterHandler(MyMsgType.UserMessage);
        
    }


    /// <summary>
    /// 服务器端有客户端连入事件
    /// </summary>
    /// <param name="netMsg">Net message.</param>
    private void OnServerConnected(NetworkMessage netMsg)
    {
        Debug.Log("One client connected to server");

        if (OneTerminalConnectedEvent != null)
        {
            OneTerminalConnectedEvent("One client connected to server");
        }
    }

    /// <summary>
    /// 服务器端有客户端断开事件
    /// </summary>
    /// <param name="netMsg">Net message.</param>
    private void OnServerDisconnected(NetworkMessage netMsg)
    {
        Debug.Log("One client connected from server");

        if (OneTerminalDisconnectedEvent != null)
        {
            OneTerminalDisconnectedEvent("One client Disconnected from server");
        }
    }

    /// <summary>
    /// 服务器端错误事件
    /// </summary>
    /// <param name="netMsg">Net message.</param>
    private void OnServerError(NetworkMessage netMsg)
    {
        ServerUnregisterHandler();
        Debug.Log("Server error");

        if (NetErrorEvent != null)
        {
            NetErrorEvent("Server error");
        }
    }

    /// <summary>
    /// 消息处理
    /// </summary>
    /// <param name="netMsg"></param>
    private void ServerRecieiveUserMessageHandler(NetworkMessage netMsg)
    {
        UserMessage Msg = netMsg.ReadMessage<UserMessage>();
        Debug.Log("Server get:" + Msg.message);

        // 这里服务器作为中转站转发信息
        ServerSendUserMessage(Msg.message);

        if (RecieiveUserMessageHandlerEvent != null)
        {
            RecieiveUserMessageHandlerEvent("Server get:" + Msg.message);
        }
    }
}

 

3、NetClient

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class NetClient
{

    public Action<string> SetupEvent;
    public Action<string> ShutdownEvent;
    public Action<string> OneTerminalConnectedEvent;
    public Action<string> OneTerminalDisconnectedEvent;
    public Action<string> NetErrorEvent;
    public Action<string> RecieiveUserMessageHandlerEvent;

    /// <summary>
    /// 网络客户端
    /// </summary>
    private NetworkClient myClient;

    private string m_ip;

    private int m_port;

    public NetClient(string ip, int port) {
        myClient = new NetworkClient();

        m_ip = ip;
        m_port = port;

    }

    /// <summary>
    /// 建立客户端
    /// </summary>
    public void SetupClient()
    {
        Debug.Log("onclick setup client");

        if (!myClient.isConnected)
        {
            Debug.Log("setup client");
            ClientRegisterHandler();
            myClient.Connect(m_ip, m_port);

            if (SetupEvent != null)
            {
                SetupEvent("client setup ok.");
            }
        }
    }

    /// <summary>
	/// 停止客户端
	/// </summary>
	public void ShutdownClient()
    {
        if (myClient.isConnected)
        {
            Disconnect();

            if (ShutdownEvent != null)
            {
                ShutdownEvent("client Disconnect.");
            }
        }
    }

    /// <summary>
    /// 断开的处理
    /// </summary>
    internal void Disconnect() {
        ClientUnregisterHandler();
        myClient.Disconnect();

        //NetworkClient.Shutdown()使用后,无法再次连接。
        //This should be done when a client is no longer going to be used.
        //myClient.Shutdown ();
    }

    /// <summary>
    /// 获取客户端连接状态
    /// </summary>
    /// <returns></returns>
    public bool GetClientConnectState() {
        return myClient.isConnected;
    }


    /// <summary>
	/// 客户端向服务器端发送信息
	/// </summary>
	public void ClientSendUserMessage(string message)
    {
        if (myClient.isConnected)
        {
            UserMessage um = new UserMessage();
            um.message = message;
            if (myClient.Send(MyMsgType.UserMessage, um))
            {
                Debug.Log("Client send:" + message);
            }
        }
    }



    /// <summary>
    /// 客户端注册事件
    /// </summary>
    private void ClientRegisterHandler()
    {
        myClient.RegisterHandler(MsgType.Connect, OnClientConnected);
        myClient.RegisterHandler(MsgType.Disconnect, OnClientDisconnected);
        myClient.RegisterHandler(MsgType.Error, OnClientError);
        myClient.RegisterHandler(MsgType.NotReady, OnClientNotReady);
        myClient.RegisterHandler(MyMsgType.UserMessage, ClientRecieiveUserMessageHandler);
        
    }

    /// <summary>
    /// 客户端注销事件
    /// </summary>
    private void ClientUnregisterHandler()
    {
        myClient.UnregisterHandler(MsgType.Connect);
        myClient.UnregisterHandler(MsgType.Disconnect);
        myClient.UnregisterHandler(MsgType.Error);
        myClient.UnregisterHandler(MsgType.NotReady);
        myClient.UnregisterHandler(MyMsgType.UserMessage);
  
    }


    /// <summary>
	/// 客户端连接到服务器事件
	/// </summary>
	/// <param name="netMsg">Net message.</param>
	private void OnClientConnected(NetworkMessage netMsg)
    {
        Debug.Log("Client connected to server");

        if (OneTerminalConnectedEvent != null)
        {
            OneTerminalConnectedEvent("Client connected to server");
        }
    }

    /// <summary>
    ///客户端从服务器断开事件
    /// </summary>
    /// <param name="netMsg">Net message.</param>
    private void OnClientDisconnected(NetworkMessage netMsg)
    {
        Debug.Log("Client disconnected from server");

        if (OneTerminalDisconnectedEvent != null)
        {
            OneTerminalDisconnectedEvent("Client disconnected from server");
        }
    }

    /// <summary>
    /// 客户端错误事件
    /// </summary>
    /// <param name="netMsg">Net message.</param>
    private void OnClientError(NetworkMessage netMsg)
    {
        ClientUnregisterHandler();
        Debug.Log("Client error");

        if (NetErrorEvent != null)
        {
            NetErrorEvent("Client error");
        }
    }

    private void OnClientNotReady(NetworkMessage netMsg)
    {
        ClientUnregisterHandler();
        Debug.Log("Client not Ready");

        
    }

    /// <summary>
	/// 客户端接收到服务器端信息事件
	/// </summary>
	/// <param name="netMsg">Net message.</param>
	private void ClientRecieiveUserMessageHandler(NetworkMessage netMsg)
    {
        UserMessage Msg = netMsg.ReadMessage<UserMessage>();
        Debug.Log("Client get:" + Msg.message);

        if (RecieiveUserMessageHandlerEvent != null)
        {
            RecieiveUserMessageHandlerEvent("Client get:" + Msg.message);
        }
    }

}


        

 

4、MyMsgType

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 自定义的消息码,别与 MsgType 重复码
/// </summary>
public class MyMsgType 
{
    public const short UserMessage = 64;
}

 

5、UserMessage

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

/// <summary>
/// 自定义信息类
/// </summary>
public class UserMessage : MessageBase
{
    // 信息
    public string message;
}

 

6、Test_NetManager

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(NetManager))]
public class Test_NetManager : MonoBehaviour
{

    /// <summary>
    /// 服务器ip地址
    /// </summary>
    public InputField ip;
    /// <summary>
    /// 服务器端口
    /// </summary>
    public InputField port;
    /// <summary>
    /// 要发送的信息
    /// </summary>
    public InputField send;

    public Text LogMessahe_Text;

    private NetManager netManager;

    // Start is called before the first frame update
    void Start()
    {
        netManager = GetComponent<NetManager>();
        LogMessahe_Text.text = "Start...";
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }


    void AddListener() {

        SetupEvent();
        ShutdownEvent();
        OneTerminalConnectedEvent();
        OneTerminalDisconnectedEvent();
        NetErrorEvent();

        RecieiveUserMessageHandlerEvent();
    }


    public void ConnectNet() {
        if (netManager != null) {
            if (string.IsNullOrEmpty(ip.text) || string.IsNullOrEmpty(port.text)) {

                Debug.Log(" Ip 或者 port 不能为空");

                return;
            }

            netManager.SetUp(ip.text, int.Parse(port.text),()=> {
                // 连接之后进行事件监听添加
                AddListener();
            });

            
        }
    }

    public void SendMessage() {
        if (netManager != null)
        {
            if (string.IsNullOrEmpty(send.text) )
            {
                Debug.Log(" send 不能为空");

                return;
            }

            netManager.SendUserMessage(send.text);

            LogMessahe_Text.text += "\r\n" + send.text;
        }
    }

    public void DisconnectNet() {
        if (netManager != null) {
            netManager.Shutdown();
        }
    }





    public void SetupEvent()
    {
        Debug.Log("SetupEvent");
        netManager.SetupEvent((str)=> {

            LogMessahe_Text.text +="\r\n" + str;
        });
    }

    public void ShutdownEvent()
    {
        netManager.ShutdownEvent((str) =>
        {

            LogMessahe_Text.text += "\r\n" + str;
        });
    }

    public void OneTerminalConnectedEvent()
    {
        netManager.OneTerminalConnectedEvent((str) =>
        {

            LogMessahe_Text.text += "\r\n" + str;
        });
    }

    public void OneTerminalDisconnectedEvent()
    {
        netManager.OneTerminalDisconnectedEvent((str) =>
        {

            LogMessahe_Text.text += "\r\n" + str;
        });
    }

    public void NetErrorEvent()
    {
        netManager.NetErrorEvent((str) =>
        {

            LogMessahe_Text.text += "\r\n" + str;
        });
    }

    public void RecieiveUserMessageHandlerEvent()
    {
        netManager.RecieiveUserMessageHandlerEvent((str) =>
        {

            LogMessahe_Text.text += "\r\n" + str;
        });
    }


}

 

七、参考工程

工程下载地址:https://download.csdn.net/download/u014361280/12471621

 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Unity是一款强大的游戏开发引擎,也被广泛用于开发大型多人在线角色扮演游戏(MMORPG)。在MMORPG开发中,网络架构设计与实现源码是非常重要的核心技术。首先,Unity客户端网络架构设计需要考虑到多个玩家之间的实时通讯和同步,以及与服务器的数据交换。 在网络架构设计上,首先需要考虑到如何处理玩家之间的实时通讯和同步。这部分源码需要实现基于UDP或TCP的网络通讯,同时考虑到玩家位置、动作、状态等数据的同步,并采用合适的压缩和插值算法来保证玩家之间的数据同步和流畅性。 其次,与服务器的数据交换也是Unity客户端网络架构设计的重要一环。这部分源码需要实现服务器通讯协议,包括登录认证、游戏数据同步、战斗事件处理等。同时需要考虑到网络延迟和丢包等问题,采用合适的重试机制和数据校验算法来保证通讯的稳定性和可靠性。 在实现上,可以采用C#等语言编写网络架构设计的源码。由于Unity本身内置了一些网络通讯的API和组件,开发者可以基于这些API和组件进行二次开发,加快开发速度和降低成本。同时,还可以借助一些开源的网络库和框架来提高网络通讯的效率和性能。 总之,Unity客户端网络架构设计与实现源码是MMORPG开发中的重要核心技术,需要综合考虑玩家之间的实时通讯和同步,以及与服务器的数据交换。通过合理的网络架构设计和源码实现,可以提高游戏的网络性能和稳定性,带来更好的游戏体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仙魁XAN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值