美文网首页网络编程unityunity学习
Unity3D-网络(一)高级开发-网络解决方案

Unity3D-网络(一)高级开发-网络解决方案

作者: 元宇宙协会 | 来源:发表于2016-12-06 00:14 被阅读5912次

    首先:Unet技术

    Unity5.1为开发者发布全新的多玩家在线工具、技术和服务。该技术的内部项目名称为 UNET,全称为 Unity Networking。
    第一阶段是多玩家在线技术基础。
    第二阶段基于第一阶段,借助模拟服务器引入服务器权威游戏 (server authoritative gaming) 概念。
    第三阶段是最后阶段,我们想通过主模拟服务器赋予协调多个模拟服务器的能力。

    为什么我们说第一阶段是多玩家在线技术基础?主要特征如下:

    1. 基于 UDP 的高性能传输层支持所有的游戏类型
    2. 底层 API (LLAPI) 通过类似套接字的接口提供全面控制
    3. 高层 API (HLAPI) 提供简单、安全的客户端/服务器网络模型
    4. 匹配服务提供基本功能,让一个用户创建多人模式并允许他人加入
    5. 中继服务器解决连接问题,以便玩家在使用防火墙的情况下能相互连接

    既然我们的目标是支持一切游戏类型和任意数量的连接,我们首先开发基于 UDP 的新型高性能传输层。尽管使用 TCP 可以很好地开发出很多游戏,快速动作游戏需要使用 UDP,因为如果数据包不按次序到达的话,TCP 会截留最近收到的数据包。
    在这个新的传输层的基础上,我们建立了两个新的 API。高层 API (HLAPI) 提供简单、安全的客户端/服务器网络模型。有些用户需要较底层的访问权限,以便实现更大的控制权限。于是,我们采用底层 API (LLAPI) 为传输层提供一个更加类似于套接字的接口。如果您是网络工程师,需要定义自定义网络模型或需要微调网络性能,LLAPI 将会符合您的兴趣。

    有了 HLAPI,就不再需要有丰富的网络知识。而如果您是网络工程师,想以自己的方式解决问题,则 LLAPI 可以帮得上忙。

    一、非授权服务器:

    不控制客户端各个玩家做什么即玩家输入与输出。客户端发送一个确定的行为结果到服务器,服务器端同步玩家的操作状态到游戏世界中,不对客户端进行影响。

    1、网络通信方式

    网络通信两种重要的方法:远程函数调用和状态同步

    01、远程过程调用

    RPC(Remote Procedure Calls) 用来调用远程计算机上某个函数的方法。
    ****这里面有两个方面:****
    01、可以从客户端调用服务器端上的某个函数
    02、从服务器端调用****所有客户端****或者某个****特定客户端****的函数

    02、状态同步

    什么时状态同步?就是同步各个客户端不断改变的数据。其实就是不断分发玩家的状态数据,这个过程消耗大量的带宽,所以我们要优化带宽数量。

    二、Hight Level API(HLAPI)

    就是Unity创建多人游戏的一个功能系统,依赖较低级别的实时通信层的传输服务,被用来处理多人游戏所需的许多常见服务。
    HLAPI:是一个权威的服务器系统。传输层支持任意形式网络拓扑结构?(可以查看我的博客:http://www.jianshu.com/p/45f8df69a743 (计算机网络)),允许同时作为客户端或服务器端,所以不需要搭建专用的服务器。

    客户端作为服务器端

    因为我们的角色都是专属的,所以有MyPlayer的概念,所以当添加一个玩家对象和链接把它们连接起来的时候,这个Player就是该玩家客户端的LocalPlayer.

    • 使用 “Network Manager”.控制游戏的网络状态。
    • 主机是一个 player 客户端。运营 “Network Manager”.游戏
    • 使用通用的序列化程序的数据进行序列化。
    • 发送和接收messages邮件。
    • 将网络的命令从客户端发送到服务器。
    • 远程过程调用 (Rpc) 从服务器向客户端。
    • 将网络的事件从服务器发送到客户端。

    案例:
    01-导入资源包:
    角色资源包
    02-创建我们的场景,如下图所示,分别保存为两个场景:scene01,scene02
    Scene01
    03-新建NetWorkManager对象来管理网络连接面板

    NetWorkManager:是一个管理网络状态的多人游戏的一个组成部分

    Paste_Image.png
    player object 被被生成是由 NetworkManager.OnServerAddPlayer 默认实现。 如果你想自定义 player object 的创建的方式,你可以重写的虚函数。
      public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
        {
           var player = (GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos, Quaternion.identity);
          NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
        }
    

    网络管理器 具有用于输入每一种模式的方法。
    NetworkManager.StartClient()
    NetworkManager.StartServer()
    NetworkManager.StartHost()
    是所有可用的脚本代码,所以它们可以被调用,从键盘输入的处理程序或自定义UI 事件 。
    networkAddress网络地址和 networkPort网络端口 属性被 使用。当启动时后的服务器 或主机 时,networkPort 成为侦听端口。
    当客户端启动时,networkAddress是要连接到的地址、networkPort 是要连接到的端口。

    NetWorkManangerHUD:运行是显示UI

    Paste_Image.png
    04-制作游戏角色,保存为预制物

    添加第一人称控制器

    Paste_Image.png Paste_Image.png 添加标示对象在网络中的位置与同步网络对象的位置组件

    NetWorkIdentity :标示游戏对象在网络中的位置

    Paste_Image.png

    NetWorkTransform:同步网络对象

    Paste_Image.png

    当网络停止时,通过停止的服务器或主机,或断开连接,客户端将加载offline脱机的场景。断开多人游戏时游戏允许自动返回到菜单场景 。

    通过调用 NetworkManager.ServerChangeScene(),游戏处于活动状态时,还可以更改场景。这将使所有当前连接的客户端更改场景,并将更新 networkSceneName,新客户还将加载新的场景。

    虽然网络的场景管理处于活动状态,调用任何游戏状态管理功能 NetworkManager.StartHost() 或 NetworkManager.StopClient() 可导致场景变化。这适用于运行时控制 UI。所以通过设置场景 并调用这些函数很容易控制流的多人游戏。

    05-同步方法1

    编译windows客户端,会发现我们的位移在同步,因为我们创建了两个游戏对象,也就存在两个相机,所以我们需要控制他们

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    
    public class Player_NetworkStep : NetworkBehaviour {
    
        public Camera firstControllerCamera;
        public AudioListener lister;
        void Start () {
            if (isLocalPlayer) // 判断是否是本地游戏对象
            {
                GameObject.FindWithTag("MainCamera").SetActive(false);
                GetComponent<CharacterController>().enabled = true;
                GetComponent<UnityStandardAssets.Characters.FirstPerson.FirstPersonController>().enabled = true;
                firstControllerCamera.enabled = true;
                lister.enabled = true;
            }
        }   
    }
    
    Paste_Image.png
    06-同步方法2

    1、删除我们的NetworkTransform,也就是不同步我们的位置消息,我们自己写脚本来同步


    300
    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    
    // 必须继承NetWorkBehaviour
    public class Player_NetworkStep : NetworkBehaviour {
        [SyncVar] // 用来标记同步成员变量,可以是任何基本数据类型,但不能是类、列表或其他集合
        Vector3 synsPos;
        public Transform myTransform;
        public float lerpRate = 15;
    
        void FixedUpdate()
        {
            TransmitPosition();
            LerpPosition();
        }
    
        void LerpPosition()
        {
            if (!isLocalPlayer)
            {
                myTransform.position = Vector3.Lerp(myTransform.position, synsPos, Time.deltaTime);
            }
        }
        [Command] // 新的网络系统中的RPC,即在客户端调用,在服务器执行。还有一种是ClientRpcCalls,正好相反
        void CmdProvidePositionToServer(Vector3 pos) // 方法以Cmd开头,使用此命令的任意参数都会被传递到服务器端
        {
            synsPos = pos;
        }
    
        [ClientCallback] // 可作为成员函数的自定义属性
        void TransmitPosition()
        {
            if (isLocalPlayer)
            {
                CmdProvidePositionToServer(myTransform.position);
            }
        }
    
    07-知识点:

    网络系统 具有网络中执行操作actions 的方法。这些类型的actions 有时是调用远程过程调用(Remote Procedure Calls)。在网络系统中有两种类型的 Rpc :

    1、Command 命令- 从客户端调用 和 运行在服务器上。
    如果需要创建一个 Command函数,需要添加[Command]自定义属性且函数必须以以Cmd开头,当这个函数在客户端连接的时候,函数的功能将在服务器端实现,使用此命令的任意参数都会被传递到服务器端
    Command命令每帧都会从客户端向服务器发送命令,这一行为会产生大量的网络通信量。


    Cmd

    默认从可靠的0通道发送命令,所以在默认情况下使用很可靠。可以通过Channel调用

    [Command(channel=1)]
    

    2、ClientRpc calls - 在服务器上调用 在 客户端上运行。
    可以从任何服务器对象发送,一个已经产生了的 NetworkIdentity 。因为服务器具有authority授权,然后没有安全性方面的问题,服务器对象能够发送这些调用。它在服务器上调用时,此函数将运行在客户端上。任何参将数自动传递给 ClientRpc 调用客户端。
    使用ClientRpc的时候也需要首方法写Rpc开头,此函数在服务器端调用,将在客户端执行其功能。


    Rpc

    当作为一个 LocalClient 的主机游戏运行时, ClientRpc 将被将被LocalClient调用 -,即使它是在相同的服务器进程。所以 LocalClients 和 RemoteClients 的行为是相同的, 对于ClientRpc 调用。

    Paste_Image.png

    [SyncVar]
    用来标记同步成员变量,可以是任何基本数据类型,但不能是类、列表或其他集合

    Paste_Image.png

    [ClientCallback]:NetworkBehaviour中成员函数的自定义属性,可以通过自定义属性来指定函数只作为服务器端函数或客户端函数

        [Client] // 只作用在客户端
        [Server] // 只作用在服务器端
        [ClientCallback] // engine调用函数,只在客户端执行
    
    Paste_Image.png
    08-保存场景出现问题解决办法:

    一般情况断网与联网不在一个场景中,所以我们要设置上次保存的场景。将Main场景中的NetWorkManager控件Copy到Menu中,设置其中的OffineScene和OnlineSecene为scene01(断网场景)和scene02(连网场景),随后删除scenes02中的NetworkManager

    同时控制我们游戏角色对象的Cube使其跟随Carema的方向变化而改变

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    using System;
    
    public class Player_syncRotation : NetworkBehaviour {
    
        [SyncVar]
        private Quaternion syncPlayerRotion;
        [SyncVar]
        private Quaternion syncCamRotation;
        [SerializeField]
        private Transform playerTrans;
        private Transform camTransform;
        private float lerpRate = 15;
    
    
        void FixedUpdate()
        {
            TransmitRotation();
            LerpRotation();
        }
    
        private void TransmitRotation()
        {
          
        }
    
        private void LerpRotation()
        {
            if (!isLocalPlayer)
            {
                playerTrans.rotation = Quaternion.Lerp(playerTrans.rotation, syncPlayerRotion, Time.deltaTime * lerpRate);
                camTransform.rotation = Quaternion.Lerp(camTransform.rotation, syncCamRotation, Time.deltaTime * lerpRate);
            }
        }
        [Command]
        void CmdProvideRotationToServer(Quaternion playerRot, Quaternion cameRot)
        {
            syncPlayerRotion = playerRot;
            syncCamRotation = cameRot;
        }
        [Client]
        void TransmitRotion()
        {
            if (isLocalPlayer)
            {
                CmdProvideRotationToServer(playerTrans.rotation, camTransform.rotation);
            }
        }
    }
    
    

    添加到角色预制物上。

    09-创建出生点:

    Start Positions
    若要控制player 被创建,在这里,你可以使用 NetworkStartPosition 组件。网络管理器查找场景中的 NetworkStartPosition 对象,如果它找到了,然后它将产生Player的位置和方向 。自定义代码可以通过NetworkManager.startPositions列表 ,访问可用的 NetworkStartPositions,也是一个 helper 函数 GetStartPosition() 对网络管理器,可以在执行 OnServerAddPlayer 用于查找起始位置。

    空物体添加子物体,在子物体添加NetworkStartPosition,多复制几个摆好位置。

    Paste_Image.png
    10-让角色移动更平滑

    修改FixedUpdate更新频率:0.02秒,打印发现Time.deltaTime = 0.02.我们是进行位置插值,所以放在我们的Update()函数中更加平滑


    Paste_Image.png

    同理也在另一个脚本进行同样的操作:


    Paste_Image.png

    我们发现间歇有点卡顿,我们对它做修改


    Paste_Image.png
    // 添加他的网络通道与网络通信间歇
    [NetworkSettings(channel = 0, sendInterval = 0.033f)]
    public class Player_syncRotation : NetworkBehaviour 
    

    三、TransPort Layer API

    除了上面的简易high Level API,Unity还提供了较低级别的传输层API.
    TransPort Layer API:能够发送和接受消息闭关表示为数组的字节,还提供了大量不同的“服务端质量”,以适应不同的场景,支持基础的网络通信服务。简单说:给你来点更加具有自由的网络通信服务。
    • 优化基于 UDP 协议。
    • Multi-channel design to avoid head-of-line blocking issues 多通道设计,以避免头的线阻塞问题
    • 每个通道支持各种levels 的服务质量 (QoS) 。
    • 灵活的网络拓扑结构,支持对等 或 客户机-服务器体系结构。

    1、两种协议:
    01-通用通信UDP

    典型工作流程
    (1)初始化网络传输层

            // 不带参数初始化
            NetworkTransport.Init();
            // 设置最大数据包为500
            GlobalConfig globalconfig = new GlobalConfig();
            globalconfig.MaxPacketSize = 500;
            NetworkTransport.Init(globalconfig);
    

    (2)配置拓扑网络

            ConnectionConfig config = new ConnectionConfig();
            // QosType.Reliable 可靠连接,确保信息传输安全
            byte reliableByteId = config.AddChannel(QosType.Reliable);
            // QosType.Unreliable 不可靠连接,传输速度快,不能保证信息传递
            byte unreliableByteId = config.AddChannel(QosType.Unreliable);
            // 网络拓扑的定义, (连接使用配置信息,允许连接数)
            HostTopology topology = new HostTopology(config, 10);
    

    (3)创建服务器主机

           // 创建主机服务(端口号:8888)
            int intHostID = NetworkTransport.AddHost(topology, 8888);
    

    (4)开始通信

        private byte error;
        private byte[] buffer;
        private int bufferLength = 1024;
    
            // 先将不同的命令发送主机并检查状态
            // 返回一个给此链接的ID
            int connetionID = NetworkTransport.Connect(intHostID, "192.168.1.131", 8888, 0, out error);
            // 此命令发送断开链接的请求
            NetworkTransport.Disconnect(intHostID, connetionID, out error);
            // 发送信息,将消息存储在缓存区消息长度为bufferLength
            NetworkTransport.Send(intHostID, connetionID, reliableByteId, buffer, bufferLength, out error);
    
    // 检测主机状态:
    void Update () {
            myConnectinID = NetworkTransport.Connect(hostId, "192.168.1.133", 8888, 0, out error);
            // 此函数返回来自任意主机的事件(recHostId返回主机ID)
            NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionID, out reliableByteId, recbuffer, bufferSize, out dataSize, out error);
             switch(recData)
             {
                case NetworkEventType.ConnectEvent:
                    if (myConnectinID == connetionID)
                    {
                        // 主动连接请求成功
                    }
                    else {
                        // 其他人连接到我
                    }
                    
                    break;
            }
     // 此函数为检测主机ID
     // NetworkTransport.ReceiveRelayEventFromHost
    
    }   
    
    02-用于WebGL的WebSockets

    Web客户端只能连接到服务器端,服务器端是一个独立的Player

    // ip为监听地址,为null,将监听所有的网路接口,服务器只支持一个WebSocket主机并在同一时间内处理常用的服务器
    NetworkTransport.AddWebSocketHost(topology,port,Ip);
    // 例如:
    NetworkTransport.AddWebSocketHost(topolagy,8888,null);
    

    四、NetworkView : 网络视图组件

    多人游戏中常用的组件,用于通过网络共享数据的组件
    使用这个组件可以定义哪个游戏对象是同步以及如何同步。因为它可以发起上面的两种通信类型:远程函数调用和状态同步。它可以指定什么数据被共享,那个对象被同步。
    为了使用包括状态同步或者远程调用等网络的功能。开发人员必须创建一个添加了NetworkView的组件的游戏对象

    五、UNET Network Messages

    除了high level facilities 的命令和 RPC 调用,还有可能将原始网络消息进行发送。
    还有一类被称为 MessageBase,可以扩展,使可序列化的网络消息类。此类有读/写对象的序列化和反序列化功能。开发人员可以执行这些函数本身,或依赖于通过网络系统自动被创建的代码生成实现。

    public abstract class MessageBase
    {
    // De-serialize the contents of the reader into this message
    public virtual void Deserialize(NetworkReader reader) {}
    // Serialize the contents of this message into the writer
    public virtual void Serialize(NetworkWriter writer) {}
    }
    有内置message 类为常用的网络messages类型:
    
    EmptyMessage
    StringMessage
    IntegerMessage
    

    发送一条消息有是 Send() 函数, 在 NetworkClient、 NetworkServer 和NetworkConnection 的工作方式相同。他们把消息 Id 和消息对象从 MessageBase 派生。

    using UnityEngine;
    using UnityEngine.Networking;
    using UnityEngine.Networking.NetworkSystem;
     
    public class SYTest : NetworkBehaviour
    {
      const short MyTestMsg = 1024;
     
      NetworkClient m_client;
     
    public void SendReadyToBeginMessage(int myID)
    {
        var msg = new IntegerMessage(myId);
        m_client.Send(MyTestMsg , msg);
    }
     
    public void Init(NetworkClient client)
    {
      m_client = client;
      NetworkServer.RegisterHandler(MyTestMsg , OnServerReadyToBeginMessage);
    }
     
    void OnServerReadyToBeginMessage(NetworkMessage netMsg)
    {
      var beginMessage = netMsg.ReadMessage<IntegerMessage>();
      Debug.Log("received OnServerReadyToBeginMessage " + beginMessage.value);
    }
    }
    
    // 声明一个自定义网络message类并 使用它:注意:ScoreMessage 类没有序列化代码。
    using UnityEngine;
    using UnityEngine.Networking;
     
    public class Scores : MonoBehaviour
    {
        NetworkClient myClient;
     
    public class MyMsgType {
    public static short Score = MsgType.Highest + 1;
    };
     
    public class ScoreMessage : MessageBase
    {
    public int score;
    public Vector3 scorePos;
    public int lives;
    }
     
    public void SendScore(int score, Vector3 scorePos, int lives)
    {
    ScoreMessage msg = new ScoreMessage();
    msg.score = score;
    msg.scorePos = scorePos;
    msg.lives = lives;
     
    NetworkServer.SendToAll(MyMsgType.Score, msg);
    }
     
    // Create a client and connect to the server port
    public void SetupClient()
    {
    myClient = new NetworkClient();
    myClient.RegisterHandler(MsgType.Connect, OnConnected);
    myClient.RegisterHandler(MyMsgType.Score, OnScore);
    myClient.Connect("127.0.0.1", 4444);
    }
     
    public void OnScore(NetworkMessage netMsg)
    {
    ScoreMessage msg = netMsg.ReadMessage<ScoreMessage>();
    Debug.Log("OnScoreMessage " + msg.score);
    }
     
    public void OnConnected(NetworkMessage netMsg)
    {
    Debug.Log("Connected to server");
    }
    }
    

    六、Unet Multiplayer Lobby:专门的NetworkManager网络管理器

    可以提供Unity多人游戏大厅(Unity Multiplayer lobby )。
    它包括:
    • 限制可以加入的players 的数量
    • 每个客户端支持多个players ,那么限制每个客户端的玩家数量
    • 防止玩家游戏in-progress时加入
    • 每名player 准备好状态,所以,游戏开始时所有玩家都是准备好了
    • 每个player 配置数据
    • 当比赛结束的时候重新加入大厅
    • 虚拟函数,它允许自定义逻辑来 lobby eventsGuiLobbyManager 是为lobby 特殊lobby 管理,提供了UI 。它可以作为一个资产包(asset package ),可以导入Unity项目轻松地添加一个lobby 到多人游戏。脚本和 UI 预置在包中可以定制,为使外观和感觉与众不同。有两种player 对象- 在NetworkLobbyManager中的每个预制的插槽(prefab slot ) :
    LobbyPlayer 对象
    • 每个player• 创建客户端连接,或添加player时 被创建
    • 一直存在直到客户端断开连接
    • 为该player在大堂准备好了flag
    • 在大厅里处理命令• 将用户脚本添加到prefab来保存特定于游戏的玩家数据
    GamePlayer 对象
    • 每个player
    • 当开始游戏场景时创建
    • 重新进入大厅时被摧毁
    • 在游戏中处理命令
    NetworkLobbyPlayer 组件用于 LobbyPlayer 的对象。它提供了一些可用于自定义大堂行为的虚函数回调

    public virtual void OnClientEnterLobby()
    {
    }
    public virtual void OnClientExitLobby()
    {
    }
    public virtual void OnClientReady(bool readyState)
    {
    }
    

    七、Internet Services : 网络服务-多用户服务器端

    这项服务是Unity支持开发者的游戏开发和发布,让开发者可以在互联网上进行通信,为开发者提供相关比赛创建和广告匹配。目前已经收钱,其实就是一个网络服务器.
    Unity 提供互联网服务,以 支持你的游戏,在整个生产和发行,其中包括:
    • Matchmaking service
    • Create matches and advertise matches.
    • List available matches and join matches.
    • Relay server
    • Game-play over internet with no dedicated server.
    • Routing of messages for participants of matches.

    1、使用网络服务先创建项目ID
    https://unrt.cloud.unity3d.com/

    八、第三方网络解决方案

    其实除却上面,我们还有更多选择,可以使用第三方的网络解决方案.
    常用的有:

    1-RakNet

    RakNet是一个基于[UDP]网络传输协议的C++网络库,允许程序员在他们自己的程序中实现高效的网络传输服务。通常情况下用于游戏,但也可以用于其它项目。

    #include <stdio.h>
    #include <conio.h>
    #include <string.h>
    #include "RakClientInterface.h" //建立客服端所需要的信息,其中包括客服端的建立,连接和数据的发送和接收
    #include "RakNetworkFactory.h" //用于管理我们在程序中使用的类,包括类内存分配和类内存的释放
    #include "RakServerInterface.h" //用于建立服务器所需用的信息,包括服务器的建立,连接和数据的发送和接收
    #include "PacketEnumerations.h" //用于处理网络引擎在运行过程中得到的信息
    Packet *packet;//网络传输中用于存储数据的一个数据结构
    /////////////////////////////////////////////////////
    /*
    Struct Packet
    {
    PlayerID playerId; //表明了包的出处。每一个连接服务器的客户端都将被分配一个唯一的ID号,用于标识自己。
    Unsigned long length; //数据长度
    Unsigned long bitsize; //比特大小
    Char *data; //包中的数据
    }
    */
    /////////////////////////////////////////////////////
    int main(void)
    {
    char str[512];
    RakClientInterface *rakClientInterface;
    RakServerInterface *rakServerInterface;
    print("(C)客服端 (S)服务器?\n");
    gets(str);
    if (str[0]=='c')
    {
    //初始化一个客户端实例,为它分配内存
    rakClientInterface=RakNetworkFactory::GetRakClientInterface();
    rakServerInterface=0;
    print("客服端已经建立。");
    }
    else
    {
    rakClientInterface=0;
    //初始化一个服务器实例,为它分配内存
    rakServerInterface=RakNetworkFactory::GetRakServerInterface();
    print("服务器已经建立。");
    }
    if (rakServerInterface)
    {
    rakServerInterface->Start(32, 0, 0, 60000);// 服务器运行在端口60000处
    /*第一个参数表明你的服务器允许同时连接多少个客户端,这个参数最大可以设置成65535;
    第二个参数做保留之用,设置成0;
    第三个参数用于设置多久进行服务器更新,参数要大于等于0,表示用每隔当前设置的毫秒数进行更新,这里设置的是0;
    最后一个参数用于设置服务器的端口;*/
    }
    else
    {
    // 运行客户端
    print("输入服务器[IP地址]:\n");
    gets(str);
    // 127.0.0.1默认
    if (str[0]==0)
    strcpy(str, "127.0.0.1");
    rakClientInterface->Connect(str, 60000, 0, 0, 0);
    /*第一个参数表示你要连接的服务器的IP地址,如果是在自己这台计算机调试程序,直接输入”127.0.0.1”或“localhost
    第二个参数表示要连接的服务器的端口;
    第三个参数表示要连接的客户端端口,主要就是用于客户端之间交换数据;
    第四个参数不要;
    第五个参数和服务器start函数中的第三个参数一样.*/
    }
    while (1)
    {
    if (rakServerInterface)
    packet = rakServerInterface->Receive();
    else
    packet = rakClientInterface->Receive();
    if (packet)
    {
    switch (packet->data[0])
    {
    case ID_REMOTE_DISCONNECTION_NOTIFICATION:
    print("另一个连接已经断开.\n");
    break;
    case ID_REMOTE_CONNECTION_LOST:
    print("一个客户端丢失连接.\n");
    break;
    case ID_REMOTE_NEW_INCOMING_CONNECTION:
    print("一个客户端已上线.\n");
    break;
    case ID_CONNECTION_REQUEST_ACCEPTED:
    print("我们的连接要求已经接受.\n");
    break;
    case ID_NEW_INCOMING_CONNECTION:
    printf("有新连接.\n");
    break;
    case ID_NO_FREE_INCOMING_CONNECTIONS:
    printf("服务器已满.\n");
    break;
    case ID_DISCONNECTION_NOTIFICATION:
    if (rakServerInterface)
    print("客户端丢失.\n");
    else
    printf("连接中断.\n");
    break;
    case ID_CONNECTION_LOST:
    if (rakServerInterface)
    printf("客户端丢失连接.\n");
    else
    printf("连接丢失.\n");
    break;
    default(
    printf("ID信息 %i 已经到达.\n", packet->data[0]);
    break;
    }
    if (rakServerInterface)
    rakServerInterface->DeallocatePacket(packet);
    else
    rakClientInterface->DeallocatePacket(packet);
    }
    }
    // TODO - Add code body here
    //getch();
    if (rakClientInterface)
    RakNetworkFactory::DestroyRakClientInterface(rakClientInterface);
    else if (rakServerInterface)
    RakNetworkFactory::DestroyRakServerInterface(rakServerInterface);
    return 0;
    }
    

    特点:
    1-高性能 在同一台计算机上,RakNet可以实现在两个程序之间每秒传输25,000条信息;
    2-容易使用 RakNet有在线用户手册,视频教程。每一个函数和类都有详细的讲解,每一个功能都有自己的例程;
    3-跨平台,当前RakNet支持Windows, Linux, Macs,可以建立在Visual Studio, GCC, Code,Blocks, DevCPP 和其它平台上。
    4-在线技术支持 RakNet有一个活跃的论坛,邮件列表,你只要给他们发信,他们可以在几小时之内回复你。
    5-安全的传输 RakNet在你的代码中自动使用SHA1,AES128, SYN,用RSA避免传输受到攻击
    6-音频传输 用Speex编码解码,8位的音频只需要每秒500字节传输。
    7-远程终端 用RakNet,你能远程管理你的程序,包括程序的设置,密码的管理和日志的管理。
    8-目录服务器 目录服务器允许服务器列举他们自己需要的客户端,并与他们连接。
    9-Autopatcher Autopatcher系统将限制客户端传输到服务端的文件,这样是为了避免一些不合法的用户将一些不合法的文件传输到服务端。
    10-对象重载系统
    11-网络数据压缩BitStream类允许压缩矢量,矩阵,四元数和在-1到1之间的实数。
    12-远程功能调用
    13-强健的通信层 可以保障信息按照不同的信道传输

    2-Photon

    https://www.photonengine.com/en/OnPremise/Dashboard
    是一款优秀的网络客户端服务器引擎,可用于与多个平台架构,是一款实时的Socket服务器和开发框架,快速、使用方便、容易扩展
    如何使用:
    http://www.mamicode.com/info-detail-1219760.html
    文档下载:
    http://download.csdn.net/download/a762923309/4936547
    特点:
    服务端架构在windows系统平台上,采用C#语言编写.
    客户端SDK提供了多种平台的开发API
    1、充分利用网络带宽
    2、采用小尺寸的二进制协议,可根据需要使用有序可靠的UDP
    3、直接支持常见的客户端平台,提供相同的工作流程
    4、封装每个客户端平台的网络层模块
    5、通信跨平台
    6、使用Dictionary发送数据,无需担心数据序列化反序列化

    3-Smart Fox Server

    SmartFoxServer 是专门为Adobe Flash设计的跨平台socket服务器,让开发者高效地开发多人应用及游戏. 该服务器主要用来创建多玩家游戏。并提供强大的制作工具.
    专门用于多用户联机游戏开发,支持Flash/Flex/Air, Java, .Net, Unity3D, Apple iPhone 开发。
    SFS Lite 此版本免费,只支持AS1.0 和 2.0 不支持AS3.0。可以迅速配置服务器,适合初学者。
    其余的服务都收费,懒得出钱.

    相关文章

      网友评论

      本文标题:Unity3D-网络(一)高级开发-网络解决方案

      本文链接:https://www.haomeiwen.com/subject/ufylmttx.html