1. 程式人生 > >unity 網路 --NetWorking

unity 網路 --NetWorking

unity 5以後底層封裝了一些network模組。比較有名的是unet 就是unityNetworkmanager,還是很強大的,用來做一些同步,聯機小遊戲還是很方便的,因為不需要我們自己再去搭建底層,只需掛載一些元件即可完成過同步。

研究unet的時候,意外發現另一套網路架構--networking。這個相比uent雖然需要我們自己去寫更多指令碼,但是相比之下,uent效能並不十分穩定,延遲也是比較高的。而networking更類似於我們自己對socket的封裝,但是這些底層結構unity已經幫我們搭建,我們可以直接呼叫。不多說,結合例子開始講解。

首先作為伺服器端,我們可以直接打包,或者在unity上直接 開啟伺服器,更加直觀不想之前只能做Windows視窗程式。

//協議類  資料結構
public class UserMsg : MessageBase
{
    public string SenderIP;
    public string message;
    public string type;
}

public class NetworkingMgr 
{
    private  static NetworkingMgr instance = null;
    public static NetworkingMgr Instance
    {
        get
        {
            if (instance == null)
                instance = new NetworkingMgr();
            return instance;
        }
    }
    public bool connected=false;
    /// <summary>  
    /// 使用者資訊分類  
    /// </summary>  
    private const short userMsg = 64;
    public string Ip; //伺服器IP
    /// <summary>
    /// 獲取本機IP
    /// </summary>
    /// <returns></returns>
    private  static string GetInternalIP()
    {
        IPHostEntry host;
        string localIP = "?";
        host = Dns.GetHostEntry(Dns.GetHostName());
        foreach (IPAddress ip in host.AddressList)
        {
            if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            {
                localIP = ip.ToString();
                break;
            }
        }
        return localIP;
    }
    #region    伺服器邏輯
    //玩家連線個數
    public int count = 0;
    private List<NetworkConnection> clients = new List<NetworkConnection>();//記錄客戶端

    /// <summary>
    /// 啟動
    /// </summary>
    /// <param name="ip"></param>
    /// <param name="port"></param>
    public void SeverStart(string ip ,int port)
    {
        if (!NetworkServer.active)
        {
            if (ip == "")
            {
                ip = GetInternalIP();//預設本機做伺服器
            }
            if (port == 0)
                port = 4455;
            Ip = GetInternalIP ();
            connected = NetworkServer.Listen(ip, port);
            Debug.Log("伺服器啟動狀態:" + connected);
            if (connected)
                ServerRegisterHandler();
        }
        else
            Debug.Log("伺服器已經開啟");
    }
    /// <summary>  
    /// 伺服器端註冊事件  
    /// </summary>  
    private void ServerRegisterHandler()
    {
        NetworkServer.RegisterHandler(MsgType.Connect, OnServerConnected);
        NetworkServer.RegisterHandler(MsgType.Disconnect, OnServerDisconnected);
        NetworkServer.RegisterHandler(MsgType.Error, OnServerError);
        NetworkServer.RegisterHandler(userMsg, ServerGet);//接受訊息
    }
    //伺服器接受到客戶端資訊
    private void ServerGet(NetworkMessage netMsg)
    {
        UserMsg Msg = netMsg.ReadMessage<UserMsg>();
        Debug.Log("收到客戶端資訊:" + Msg.message);
        ServerSendAll(Msg);
        //for (int i = 0; i < clients .Count ; i++)
        //{
        //    SeverSendToClient(Msg, netMsg);
        //}
    }
    //伺服器錯誤事件
    private void OnServerError(NetworkMessage netMsg)
    {
    }
    //有客戶端斷開事件
    private void OnServerDisconnected(NetworkMessage netMsg)
    {
        count--;
        clients.Remove(netMsg.conn);
        UserMsg msg = new UserMsg()
        {
            message = "掉線!",
            SenderIP = netMsg.conn.address,
            type = "OutLine",
        };
        ServerSendAll(msg);
    }
    // 有客戶端登入時呼叫
    private void OnServerConnected(NetworkMessage msg)
    {
        count++;
        clients.Add(msg.conn);
        Debug.Log("玩家登入:" + msg.conn .address);
    }
    //伺服器廣播
    public void ServerSendAll(UserMsg um)
    {
        if (NetworkServer.active)
        {
            if (NetworkServer.SendToAll(userMsg, um))
            {
                Debug.Log("Server send:" + um.message);
            }
        }
    }
    //傳送給指定客戶端
    public void SeverSendToClient(UserMsg um, NetworkMessage netMes)
    {
        if (NetworkServer.active)
        {
            Debug.Log("向客戶端傳送資料:" + um.message + " ---- " + DateTime.Now);
            NetworkServer.SendToClient(netMes.conn .connectionId  , userMsg, um);
        }
    }
    //停止伺服器
    public void ShutdownServer()
    {
        if (NetworkServer.active)
        {
            ServerUnregisterHandler();
            NetworkServer.DisconnectAll();
            NetworkServer.Shutdown();

            if (!NetworkServer.active)
            {
                Debug.Log("shut down server");
            }
        }
    }
    //伺服器登出事件
    private void ServerUnregisterHandler()
    {
        NetworkServer.UnregisterHandler(MsgType.Connect);
        NetworkServer.UnregisterHandler(MsgType.Disconnect);
        NetworkServer.UnregisterHandler(MsgType.Error);
        NetworkServer.UnregisterHandler(userMsg);
    }
    #endregion
}

以上只是一個簡單是伺服器端,當然,如果你想要更視覺化,可以自己做些酷炫介面的。

然後是客戶端

public class NetworkingMgr 
{
    private  static NetworkingMgr instance = null;
    public static NetworkingMgr Instance
    {
        get
        {
            if (instance == null)
                instance = new NetworkingMgr();
            return instance;
        }
    }
    public bool connected=false;
    /// <summary>  
    /// 使用者資訊分類  
    /// </summary>  
    private const short userMsg = 64;
  public NetworkClient myClient;//本機客戶端
    /// <summary>
    /// 做客戶端 連線伺服器
    /// </summary>
    /// <param name="ip"></param>
    /// <param name="port"></param>
    public void  Connected(string ip, int port,Action callback)
    {
        if (ip == "")
        {
            ip = GetInternalIP();
        }
        if (port == 0)
            port = 4455;
        myClient = new NetworkClient();
        myClient.Connect(ip, port);
        myClient.RegisterHandler(MsgType.Connect, (netMsg) => 
        {
            Ip = GetInternalIP ();
            connected = myClient.isConnected;
            Debug.Log("連線成功!!!");
            if (callback != null)
                callback.Invoke();
        });
    }
    //向伺服器傳送資訊
    public void ClientSend(UserMsg um)
    {
        if (myClient.isConnected)
        {
            um.SenderIP = Ip;
            if (myClient.Send(userMsg, um))
            {
                Debug.Log("傳送成功!!");
            }
        }
    }
    // 客戶端註冊事件  
    public  void ClientRegisterHandler()
    {
        connected = true;
        //myClient.RegisterHandler(MsgType.Connect, OnClientConnected);
        myClient.RegisterHandler(MsgType.Disconnect, OnClientDisconnected);
        myClient.RegisterHandler(MsgType.Error, OnClientError);
        //myClient.RegisterHandler(userMsg, ClientGet);
    }
    //客戶端接受到伺服器資訊
    //private void ClientGet(NetworkMessage netMsg)
    //{
    //    UserMsg Msg = netMsg.ReadMessage<UserMsg>();
    //    Debug.Log("收到伺服器資訊:"+Msg.message);
       
    //}
    //客戶端錯誤事件
    private void OnClientError(NetworkMessage netMsg)
    {
    }
    //客戶端沖服務器斷開事件
    private void OnClientDisconnected(NetworkMessage netMsg)
    {
    }
    //客戶端連線到伺服器事件
    //private void OnClientConnected(NetworkMessage netMsg)
    //{
    //    connected = myClient.isConnected;
    //    Debug.Log("連線成功!!!");
    //}

    // 停止客戶端  
    public void ShutdownClient()
    {
        if (myClient.isConnected)
        {
            ClientUnregisterHandler();
            myClient.Disconnect();

            //NetworkClient.Shutdown()使用後,無法再次連線。  
            //This should be done when a client is no longer going to be used.  
            //myClient.Shutdown ();  
        }
    }
    // 客戶端登出事件  
    private void ClientUnregisterHandler()
    {
        myClient.UnregisterHandler(MsgType.Connect);
        myClient.UnregisterHandler(MsgType.Disconnect);
        myClient.UnregisterHandler(MsgType.Error);
        myClient.UnregisterHandler(userMsg);
    }

這些方法介面都是unity封裝完成開放的,直接呼叫就行,啟動一個伺服器,一個客戶端,測試,通過!!


若有問題歡迎諮詢指正!!!.


demo下載地址:https://download.csdn.net/download/nt_xs_j/10502072