一、PhotonServer介绍
PhotonServer是一款服务器软件,它有它的dll,自带的服务,提供我们去使用,完成类似于Socket的功能。
二、PhotonServer的下载
上官网,下载On-Premises的,例如我下载的是Windows版本的On-Premises系列PhotonServer。
官网网址:https://www.photonengine.com/en/sdks
三、创建我们的Server类库
在VS下新建一个工程,名字随意,然后在该工程下新建类库:MyServer
接下来我们要引用如下dll
以下在解压后的PhotonServer文件夹的lib文件夹下找到
log4net.dll:配置日志文件所需的库 (可不引入)
Photon.SocketServer.dll:使用PhotonServer自带的服务的库(必须)
PhotonHostRuntimeInterfaces.dll:PhontonServer服务自身需要的实时接口库(可不引入)
ExitGames.Logging.Log4Net.dll:配置PhotonServer日志文件所需的库(可不引入)
ExitGamesLibs.dll:PhotonServer自身需要的库(可不引入)
------------------------------------------------------------------------------------------
这下面2个dll要分开找,一个是在MySql的C:\Program Files (x86)\MySQL\MySQL Installer for Windows(MySql.Data.dll)
、另一个是在NHibernate-5.1.3-bin下的\Required_Bins文件夹下(NHibernate.dll)(5.1.3是我下载NHibernate版本)
这是我的一个博客介绍NHibernate的 -> https://blog.youkuaiyun.com/qq_39574690/article/details/80799692
MySql.Data.dll:连接MYSQL数据库所需的库(必须) 我那个MySql Installer for Windows文件夹找不到的话,那么可以直接在MySQL主目录下进行搜索,一般都能找到,而且有些人可能会有多个相同的dll,因为不同版本的MySql中都有这样的一个dll,所以选择好你对应的版本dll.
NHibernate.dll:映射数据库所需的库(可不引入)
工程的程序集名称和默认命名空间都改为MyServer,在G:\Photon-OnPremise-Server-SDK_v4-0-29-11263\deploy\下新建一个叫MyServer的文件夹,在该文件夹下新建一个叫bin的文件夹,然后把工程的生成输出路径改为在这个bin文件夹。非常的关键这一步!
服务器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Photon.SocketServer;
namespace MyServer
{
class MyServer:ApplicationBase
{
//接收到客户端时的调用该方法
protected override PeerBase CreatePeer(InitRequest initRequest)
{
return new ClientPeer(initRequest);//直接返回一个继承于ClientPeer的对象给PhotonServer进行管理
}
//服务器启动后调用该方法(仅一次)
protected override void Setup()
{
}
//服务器关闭前调用该方法(仅一次)
protected override void TearDown()
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Photon.SocketServer;
namespace MyServer
{
//一个ReceptPeer代表着一个客户端与服务器的连接,这个连接放在服务器端对它进行管理
public class ReceptPeer : Photon.SocketServer.ClientPeer
{
//构造方法 InitRequest是初始化ClientPeer的参数,交给父类构造方法处理它
public ReceptPeer(InitRequest initRequest) : base(initRequest)
{
}
//该客户端断开服务器时调用
protected override void OnDisconnect(PhotonHostRuntimeInterfaces.DisconnectReason reasonCode, string reasonDetail)
{
}
//接收到客户端请求时调用
protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
}
}
}
打开PhotonServer的配置文件(PhotonServer.config),这个文件在G:\Photon-OnPremise-Server-SDK_v4-0-29-11263\deploy\bin_Win64,用VS打开该文件。
里面有什么我目前还不懂,也不需要弄太懂,就是把里面的<MMoDemo >... ...</MMoDemo> 的全部复制,粘贴在</Configuration>前面,然后修改为我们自己的应用程序Photon服务器端,如下:
注释我会用//来标明,复制粘贴这段代码的人注意了,要把//... 删掉!!不然会出错,在后面标注了//的都是我们要改的地方!
<!-- Instance settings -->
<MyGameInstance //应用程序配置名称,随意起的 用以区分不同应用配置,因为一个PhotonServer能给多个应用程序提供服务的
MaxMessageSize="512000"
MaxQueuedDataPerPeer="512000"
PerPeerMaxReliableDataInTransit="51200"
PerPeerTransmitRateLimitKBSec="256"
PerPeerTransmitRatePeriodMilliseconds="200"
MinimumTimeout="5000"
MaximumTimeout="30000"
DisplayName="My Game" //在PhotonSever右击出现的菜单选项的名字
>
<!-- 0.0.0.0 opens listeners on all available IPs. Machines with multiple IPs should define the correct one here. -->
<!-- Port 5055 is Photon's default for UDP connections. -->
<UDPListeners>
<UDPListener
IPAddress="0.0.0.0"
Port="5055"
OverrideApplication="MyGame1"> //改为我们的应用程序名,这个也是随意起的。
</UDPListener>
</UDPListeners>
<!-- 0.0.0.0 opens listeners on all available IPs. Machines with multiple IPs should define the correct one here. -->
<!-- Port 4530 is Photon's default for TCP connecttions. -->
<!-- A Policy application is defined in case that policy requests are sent to this listener (known bug of some some flash clients) -->
<TCPListeners>
<TCPListener
IPAddress="0.0.0.0"
Port="4530"
PolicyFile="Policy\assets\socket-policy.xml"
InactivityTimeout="10000"
OverrideApplication="MyGame1" //改为我们的应用程序名,同上,要保证一致!
>
</TCPListener>
</TCPListeners>
<!-- Defines the Photon Runtime Assembly to use. -->
<Runtime
Assembly="PhotonHostRuntime, Culture=neutral"
Type="PhotonHostRuntime.PhotonDomainManager"
UnhandledExceptionPolicy="Ignore">
</Runtime>
<!-- Defines which applications are loaded on start and which of them is used by default. Make sure the default application is defined. -->
<!-- Application-folders must be located in the same folder as the bin_win32 folders. The BaseDirectory must include a "bin" folder. -->
<Applications Default="MyGame1"> //Default的内容改为应用程序名
<!-- MMO Demo Application -->
<Application
Name="MyGame1" //应用程序名
BaseDirectory="MyServer" //MyServer类库的输出路径的外一层目录名称
Assembly="MyServer" //MyServer类库的程序集名称
Type="MyServer.MyServer" //指定服务器启动的是我们自己的MyServer类库,这个类库就是一个服务器。不过我们用了PhotonServer一些服务。所以启动的时候是在PhotonServer启动,而不是像我们之前那样用个控制台应用程序当服务器
ForceAutoRestart="true"
WatchFiles="dll;config"
ExcludeFiles="log4net.config">
</Application>
</Applications>
</MyGameInstance>
然后保存下这个文件,注意要保存!不然也没法生效,这样,重启PhotonServer.exe当我们再次右击PhotonServer应用程序的时候会出现名叫My Game的菜单项了。PhotonServer.exe在G:\Photon-OnPremise-Server-SDK_v4-0-29-11263\deploy\bin_Win64下,因为我的是WIN64平台,所以是bin_Win64,如果是别的平台,上面的配置文件也要在相应的平台文件下找到去进行修改,配置好自己的应用服务器。
Unity客户端:
新建一个叫PhotonServer的物体,挂载下面C#脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ExitGames.Client.Photon;
public class PhotonEngine : MonoBehaviour,IPhotonPeerListener {
public static PhotonEngine Instance;
public static PhotonPeer Peer
{
get
{
return peer;
}
}
private static PhotonPeer peer;
//Debug返回时候调用
public void DebugReturn(DebugLevel level, string message)
{
}
//服务器直接发送Event消息给客户端,然后在这里处理
public void OnEvent(EventData eventData)
{
}
//客户端发送请求,服务器处理结束后发送回来的响应消息到达这里进行处理
public void OnOperationResponse(OperationResponse operationResponse)
{
}
//peer的状态发生变化的时候都会调用该方法
public void OnStatusChanged(StatusCode statusCode)
{
}
private void Awake()
{
if(Instance==null)
{
Instance = this;
DontDestroyOnLoad(this.gameObject);
}
else if(Instance!=this)
{
Destroy(this.gameObject);
return;
}
}
//当有一个客户端启动游戏后就会立马进行与服务器连接
void Start () {
//通过Listener接收服务器端的响应 使用自带的监听器 this,使用UDP协议 ConnectionProtocol.Udp
peer = new PhotonPeer( this , ConnectionProtocol.Udp);
//下面的配置信息是PhotonServer.config配置文件的第三个Instance中的配置信息,即我们自己的应用程序配置信息
//连接本地服务器PhotonServer(固定不变),UDP配置端口是5055,应用名称是MyGame1,在<Application>标签的应用名称!(若非本地的改为你服务器的IP)
peer.Connect("127.0.0.1:5055", "MyGame1");
}
void Update () {
//维持服务连接,这样才会发起连接请求Connect,以及一些信息的发送
peer.Service();
}
void OnDestroy()
{
if (peer!=null && peer.PeerState == PeerStateValue.Connected)
{
//断开连接
peer.Disconnect();
}
}
}
当我们需要发送消息给服务器时候,只需要PhotonEngine.Peer.OpCustom(byte,Dictionary<byte,object>,bool)方法发送,第一个参数是消息编号,这个消息编号会封装入接收方(服务器)的OperationRequest中,即OperationRequest.OperationCode就是它。第二个参数是参数列表,它是一个字典,第三个参数设置为true代表准必须发送消息成功,为false就尽力而为地发送消息(即发送一次,发送出去就不管了)。
当我们使用该方法发送消息出去后会在服务器端的ReceptPeer类的OnOperationRequest信息处理,它的OperationRequest就带有那个消息编号和消息参数列表,第二个参数没用过。
处理客户端请求的时候,根据消息编码的不同 用不同的处理方法,我们可以用枚举来当消息编号,在服务器端和客户端两边用一个叫Common类库,里面设置一些枚举来区分我们的各种请求。
因为,我们的参数列表是,Dictionary<byte,object>字典,所以我们又可以在Common类库下在弄一个enum来区分开不同的参数。
而又因为,我们服务器端可以直接发送Event给客户端的,所以我们再创一个enum来区分开不同的Event事件!
PhotonServer方法总结:
1.ClientPeer类的SendEvent(EventData,SendParameters) 发送事件
参数1:EventData类
EventData成员:Code 事件消息编号
Parameters 参数列表一样是一个Dictionary<byte,object>
参数2:SendParameters(一般没有用到),若在处理客户端请求方法中的话,那么直接用方法自带的SendParameters即可,若没有外部传递来的SendParameters,那么直接new SendParameters()
2.ClientPeer类的SendOperationResponse(OperationResponse,SendParameters) 发送响应
(注意这个方法只能在服务器端的处理请求方法中使用,如果在其他地方使用,是无效的)
参数1:OperationResponse类
成员:
OperationCode 响应编号 (一般都与发送编号相同,特例除外)
ReturnCode 返回参数(short类型),只能保存一个参数
Parameters 参数列表(同上)
参数2 :SendParameters (同上)
3.发送消息方法:PhotonPeer类的OpCustom(byte,Dictionary<byte,object>,bool)
参数1:消息编号
参数2:发送的参数列表
参数3:保证发送成功标志位,为true表示保证发送成功,为false 则不保证。