Unity5.x实现简易语音聊天(三)Client-Server通信

来源:互联网 发布:电脑桌面日程表软件 编辑:程序博客网 时间:2024/05/22 12:15

0. 背景

文(一)讲述了本文讲述了如何使用既有材料和Unity,构建一个简单的语音聊天客户端,服务端程序。上文(二)讲述了语音录音和播放的几个重要的步骤,同时也给出了步骤的相关API。本文将会讲述如何使用Unity Network相关组件实现Client-Server通信。

1. Client-Server通信

Client-Server通信在语音聊天中起到了最基础的作用转发客户端消息广播给所有客户端,如图1 所示:

这里写图片描述
图1. Client-Server通信结构图

Client-Server通信有很多方式,最经典的是网络Socket模块,Socket编程的流程如图2所示:

这里写图片描述
图2. 经典网络socket模块

当然本文中Server也是非常的简陋,而且既然使用的是Unity,而Unity提供了非常强大的类库Network,和非常便捷的组件NetworkView组件,即可解决CS通信问题。在(一)中已经使用了NetworkView

2. Class "Network"

Network类是Unity网络模块的核心实现,它提供了基本所有的接口和网络所需参数。例如构建服务端,连接,以及各种回调事件。

//(1)构建服务器并初始化static NetworkConnectionError InitializeServer(int connections, int Port, bool useNat);//(2)客户端连接服务端static NetworkConnectionError Connect(string IP, int remotePort, string password = "")//(3)客户端成功连接服务端,回调客户端void OnConnectedToServer()//(4)客户端(主动或被动)从服务端断开,回调客户端;//也可能是服务端连接不上网,回调服务端void OnDisconnectedFromServer(NetworkDisconnection info)//(5)有客户端连接上服务端,回调服务端void OnPlayerConnected(NetworkPlayer player)//(6)某客户端从服务端断开,回调服务端void OnPlayerDisconnected(NetworkPlayer player)

这些接口保证了Server端的Socket创建,绑定,监听,接收客户端连接;Client端的Socket创建,连接的功能,为CS通信提供了基础。

3. Component "NetworkView"

当游戏存在多玩家时,NetworkView组件是一个绑定素材。关于NetworkView的学习可以参考Unity doc和YouTube Unity3D Networking。

关于NetworkView组件的具体可查看下图:

这里写图片描述
图3. NetworkView组件的具体信息

如图3.所示,NetworkView组件中有五个重要的变量:viewID, isMine, Observed, stateSynchronization, owner,在图中也给出了解释。NetworkView组件有归属的概念,如果一个GameObject是通过Network类本地创建的(Network.Instantiate),那么GameObejct中的NetworkView属于Network.Instantiate创建返回的GameObejct,其他客户端因同步好后,对应obejct的NetworkViewisMine=false。而owner也返回的是本客户端的Player

NetworkView组件在Inspect中,需要设置StateSynchronizationObserved,如图4所示。

这里写图片描述
图4. NetworkView组件在Inspect设置

StateSynchronizationOff, Unreliable, ReliableDeltaCompressed三个枚举值。Off为不发送任何数据,也不会调用OnSerializeNetworkView接口;Unreliable是强制的发送数据,不保证安全、有序,类似UDP;ReliableDeltaCompressed为安全有序的发送所有数据,类似TCP。Observerd是设置需要观察的脚本组件,可以在这个脚本里面override OnSerializeNetworkView接口即可达到CS同步消息。

在本语音聊天中(一)步骤3.b新建Unity 2D Project中,新建一个VoiceChat_NetworkProxy就加入了一个NetworkView组件,并且设置Observerd属性为VoiceChatNetworkProxy.cs脚本。

以下是两种同步机制:OnSerializeNetworkViewRPC

a. OnSerializeNetworkView

二进制流同步接口接口OnSerializeNetworkView签名具体如下:

//(7)Client-Server字节流同步,回调客户端,服务端void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)

其中参数BitStream是Unity内建的类,它将一些主要的类型的序列化进行了封装,例如bool,char,short,int,float,也有Unity内建的类型,例如Quaternion,Vector3,NetworkPlayer,NetworkViewID

在(二)的图4,图5中,叙述了序列化和反序列化语音数据的步骤是在NetworkProxy中,将VoicePacket数据通过BitStream.Serialize接口序列化成二进制流,如下代码所示:

///material.Networking.VoiceChatExtensions.cs// 序列化public static void WritePacket(this BitStream stream, VoiceChatPacket packet)// 反序列化public static VoiceChatPacket ReadPacket(this BitStream stream)

二进制流通过OnSerializeNetworkView实现CS通信:

//(7)Client-Server字节流同步,回调客户端,服务端void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info){    if (stream.isWriting) // 序列化    {        // 如果是录音客户端,需要将语音数据序列化(WritePacket方法)        TODO:...    }    else // stream.isReading == True // 反序列化    {        if (Network.isServer)        {            // server不需要数据,故什么都不做,语音数据转发由Network类代劳        }        else // Network.isClient == True        {            // 如果是其他客户端,反序列化(ReadPacket方法),并播放语音            TODO:...        }    }}

b. RPC

当然可以通过NetworkView.RPC来实现CS的远程方法调用(在5.4版本已经废弃了)。

public void RPC(string name, RPCMode mode, params object[] args);

参数name为rpc名字;
参数mode为发送的模式:All, AllBuffered, Others, OthersBuffered, Server
参数args为rpc方法需要携带的参数。

在使用RPC时,需要遵守如下规则:

  1. 调用的方法之上写[RPC]以表示这个方法是RPC方法;
  2. 要在调用方法的组件的GameObejct中attach一个NetworkView组件;
  3. 如果只想调用RPC,则将NetworkViewobserverd设置为None,stateSynchronization设置为Off
  4. RPC方法名在所有脚本中唯一,如果有多个相同名RPC,只会调用一个。

4. 总结

本文将会讲述如何使用Unity Network相关组件实现Client-Server通信。因为本文的语音聊天的CS通信需求十分简单,所以只是用了Unity自带的网络模块。如果是较大的项目,建议使用最经典的Socket网络模块,以及自定义传输协议和RPC。

至此语音聊天demo共计三部分完。

1 0
原创粉丝点击