快速了解和使用Photon Server

Photon Server的使用

又要过去一个寒假了,然而在家什么事都没干成,在一个偶然的机会下,跟着网上的教程学习了一下Photon Server,然后又觉得无聊,所以就顺便写篇博客,介绍一下Photon Server和总结一下如何使用。

一、Photon Server是什么?

    Photon Server是一套套装的游戏服务器,以往开发线上游戏都必需自行花费大笔的研发资金和人力先从研发游戏引擎和伺服器开始,後来慢慢的游戏引擎开始走向套装化,研发人员有许多现成的游戏引擎可以选择,像是unreal或是unity等等,接著,游戏服务器也开始朝套装发展,市面上常见的套装Game Server有 smart fox server 、 electro server 5 、 Photon等等,这几个都是非常优秀的套装伺服器,市面上非常多的FB游戏都是利用这些套装伺服器作为通讯用平台,都是经过市场验证过的产品。

Photon Server的核心是用C++开发,不同 於其他伺服器采用的java,因此在效能上凌驾於其他server不少,在 Server 端 Script 采用C#语言,算是一种很容易学习的语言,Photon的Client端支援C++、.net、java、html5 、flash、Unity、mamalade、iOS、android、winphone、cocos等,市面上常见的平台全部都有支援,使用容易、效能高、支援平台多,这些优点让photon成为一个优越的套装socket server。

 

二、如何下载Photon Server?

废话少说,直接来说一下如何下载Photon Server搭建的游戏服务器,首先需要下载Photon Server 在                                                                                  https://www.photonengine.com/en/OnPremise/Download 中下载。(第一个就是,可能需要官网账号才能下载,所以注册一个吧)

 

 

 

下载之后选个目录点击安装就可以了,完全是傻瓜式安装,没有什么需要注意的地方。

 

三、Photon Server的安装目录

安装好了之后,找到安装目录。会有四个文件夹

 

 

deploy主要存放photon的服务器控制程序和服务端Demo

doc顾名思义就是存放相关文档的

Lib存放开发服务端所需要的类库

src-server存放服务端Demo的源代码

然后点击deploy进去之后

 

 

启动服务器的程序在bin_Win32bin_win64,看自己的电脑用的是32位还是64

启动的程序为

 

 

四、Photon Server的第一个程序的配置

首先打开visual studio新建一个C#的类库,特别注意是类库,笔者第一次时建的是C#应用程序,结果导致需要一个Main函数作为程序的入口,而Photon Server的程序入口不是Main函数。

建好项目之后,需要指定一下我们项目所需要Photon所需要的类库,需要引用一下这些类库,首先找到Photon的安装目录的lib,在里面找到ExitGamesLibs.dll、Photon.SocketServer.dll、PhotonHostRuntimeInterfaces.dll、这三个程序集,引用一下

 

 

 

 

原理上只需要上面的三个程序集,但是为了开发时方便需要将调试信息和错误输出到日志上,所以也在lib中将log4net.dllExitGames.Logging.Log4Net.dll引用一下,写一个日志输出的函数需要,在此也引用一下。日志输出需要一个输出文件,在此也特别说明一下在安装目录下E:\Photon\Photon-OnPremise-Server-SDK_v4-0-29-11263\src-server\Loadbalancing\LoadBalancing,找到log4net.config文件,将它拷贝到工程目录下和代码放到一块,需要修改一下内容为:

<?xml version="1.0" encoding="utf-8" ?>

<log4net debug="false">

 

  <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">

    <layout type="log4net.Layout.PatternLayout">

      <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %-30.30c{2} %m% [%t]%n" />

    </layout>

  </appender>

 

  <!-- "normal" log file appender -->

  <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">

    <file type="log4net.Util.PatternString" value="%property{Photon:ApplicationLogPath}\\%property{LogFileName}.log" />

    <encoding value="utf-8" />

    <param name="AppendToFile" value="true" />

    <param name="MaxSizeRollBackups" value="1" />

    <param name="MaximumFileSize" value="250MB" />

    <param name="RollingStyle" value="Size" />

    <param name="LockingModel" type="log4net.Appender.FileAppender+MinimalLock" />

    <layout type="log4net.Layout.PatternLayout">

      <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />

    </layout>

  </appender>

 

  <!-- logger -->

  <root>

    <level value="INFO" />

    <appender-ref ref="LogFileAppender" />

    <appender-ref ref="ConsoleAppender" />

  </root>

 

  <!-- operation data logger -->

  <!-- set level to DEBUG to enable operation data logging-->

  <logger name="OperationData">

    <level value="INFO" />

  </logger>

 

  <!-- override log level for certain classes / namespaces -->

 

  <!-- set to DEBUG to enable logging for the Photon.SocketServer namespace -->

  <logger name="ExitGames">

    <level value="INFO" />

  </logger>

 

  <!-- set to DEBUG to enable logging for the Photon.SocketServer namespace -->

  <logger name="Photon.SocketServer">

    <level value="INFO" />

  </logger>

 

 

</log4net>

 

 

 

五、Photon Server的第一个程序

完成上面的配置之后,就可以开始编写代码了,新建一个类,

MyServer,继承一个抽象类ApplicationBase然后实现抽象类中的方法,特别注意这个抽象类,它是整个服务端的入口

  class MyServer : ApplicationBase

    {

 

        private static ILogger log =  

                             ExitGames.Logging.LogManager.GetCurrentClassLogger();

 

        //日志输出

        public static void Log(string str)

        {

            log.Info(str.ToString());

        }

     

       protected virtual void InitLogging()

        {

     ExitGames.Logging.LogManager.SetLoggerFactory(Log4NetLoggerFactory.Instance);

 GlobalContext.Properties["Photon:ApplicationLogPath"] =  

 Path.Combine(this.ApplicationRootPath, "log");

            GlobalContext.Properties["LogFileName"] = "My" + this.ApplicationName;

            XmlConfigurator.ConfigureAndWatch(new  

            FileInfo(Path.Combine(this.BinaryPath, "log4net.config")));

        }

 

 

        //创建连接

        protected override PeerBase CreatePeer(InitRequest initRequest)

        {

            return new MyClient(initRequest);

        }

 

        //服务器启动时调用

        protected override void Setup()

        {

             InitLogging();

             Log("Setup ok.");

        }

      

       

        //服务器停止时调用

        protected override void TearDown()

        {

            Log("TearDown ok.");

        }

    }

接下来新建一个MyClient类,作为管理连接到服务器的每一个客户端,每连接进来一个客户端就会创建一个MyClient的对象用来管理客户端,MyClient实现ClientPeer抽象类,这个类是用来与客户端通信使用的,然后客户端的状态发生改变时就会调用相应的方法

 public class MyClient : ClientPeer

    {

       

        public MyClient(InitRequest initRequest) : base(initRequest)

        {

            MyServer.Log("客户端上线");

          

        }

        //客户端断开连接

        protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail)

        {

     

            MyServer.Log("客户端下线");

        }

        //客户端发起请求

        protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)

        {

            MyServer.Log("客户端发送请求");

        }

    }

 

 

 

六、配置启动Photon Server

写完最基本的两个类之后就可以配置启动服务器了,首先找到安装photon的目录E:\Photon\Photon-OnPremise-Server-SDK_v4-0-29-11263\deploy\bin_Win64

我用的是64位系统,所以找到bin_win64,如果是32位就找bin_win32,找到里面的PhotonServer.config,编辑它,在文件的后面加上(和此文件前面的内容差不多,可以复制过来修改)

<ChatServer  <!-- 这里的名称为服务器名称,可随意取-->

MaxMessageSize="512000"

MaxQueuedDataPerPeer="512000"

PerPeerMaxReliableDataInTransit="51200"

PerPeerTransmitRateLimitKBSec="256"

PerPeerTransmitRatePeriodMilliseconds="200"

MinimumTimeout="5000"

MaximumTimeout="30000"

DisplayName="ChatServer">

 

<!-- 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="ChatRoom"><!-- 这里的名称为项目名称-->

</UDPListener>

 

 

</UDPListeners>

 

<!-- 0.0.0.0 opens listeners on all available IPs. Machines with multiple IPs should define the correct one here. -->

<TCPListeners>

<!-- TCP listener for Game clients on Master application -->

<TCPListener

IPAddress="0.0.0.0"

Port="4530"

OverrideApplication="ChatRoom"<!-- 这里的名称为项目名称-->

PolicyFile="Policy\assets\socket-policy.xml"

InactivityTimeout="10000"

>

</TCPListener>

 

 

<!-- DON'T EDIT THIS. TCP listener for GameServers on Master application -->

<TCPListener

IPAddress="0.0.0.0"

Port="4520">

</TCPListener>

</TCPListeners>

 

<!-- Policy request listener for Unity and Flash (port 843) and Silverlight (port 943)  -->

<PolicyFileListeners>

  <!-- multiple Listeners allowed for different ports -->

  <PolicyFileListener

IPAddress="0.0.0.0"

Port="843"

PolicyFile="Policy\assets\socket-policy.xml">

  </PolicyFileListener>

  <PolicyFileListener

IPAddress="0.0.0.0"

Port="943"

PolicyFile="Policy\assets\socket-policy-silverlight.xml">

  </PolicyFileListener>

</PolicyFileListeners>

 

 

 

 

<!-- 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="ChatRoom"> <!-- 这里的名称为项目名称-->

<Application

Name="ChatRoom" <!-- 这里的名称为项目名称-->

BaseDirectory="ChatRoom"<!-- 这里的名称为deploy文件夹下的启动服务器的

                                                                    文件夹名称 -->

Assembly="ChatRoom"

Type="ChatRoom.MyServer"<!-- 这里的名称为程序入口的类-->

ForceAutoRestart="true"

WatchFiles="dll;config"

ExcludeFiles="log4net.config"

>

</Application>

 

 

<!-- CounterPublisher Application -->

<Application

Name="CounterPublisher"

BaseDirectory="CounterPublisher"

Assembly="CounterPublisher"

Type="Photon.CounterPublisher.Application"

ForceAutoRestart="true"

WatchFiles="dll;config"

ExcludeFiles="log4net.config">

</Application>

</Applications>

</ChatServer>

写好配置文件之后在deploy文件夹中新建一个文件夹,最后取和项目名称一样,再在里面新建一个bin文件夹存放项目生成的程序集

 

 

 

 

搞定这些工作之后就开始生成程序集,回到vs,找到写好的项目,右键点击项目名选择属性

 

 

选择生成,选择新建好的bin文件夹

 

最后点击生成解决方案

 

 

然后回到安装目录下的bin_win64,找到PhotonControl.exe,双击运行,然后会发现电脑右下角会出多了一个图标,右键就会发现刚刚配置文件中的服务器,点击启动

 

 

 

 

然后发现将鼠标停在图标上会有提示Photon running,这时服务器就成功启动了

 

 

 

 

 

 

客户端的编写(unity)

 

一、客户端的配置

首先客户端笔者使用unity编写,其他平台的大同小异,读者可自行研究一下,首先客户端需要一些特定的类库,所以先找到安装目录的lib目录下找到Photon3Unity3D.dll这个程序集,将它复制一份到unity的项目目录下(事先在unity中新建一个工程,在工程Assets目录下新建一个Plugins目录用来存放程序集)。这样就配置好客户端所需的程序集了。

二、客户端脚本的编写

在工程里新建一个脚本PhotonManager,将脚本挂载到主摄像机上,双击脚本开始编辑,首先引入命名空间using ExitGames.Client.Photon; 客户端和服务器需要用到IPhotonPeerListener这个接口,所以实现这个接口

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using ExitGames.Client.Photon;

using System;

using Common.Code;

 

public class PhotonManager : MonoBehaviour,IPhotonPeerListener {

 

    private static PhotonManager instance = null;

    public static PhotonManager Instance { get { return instance; } }

 

    //用来和服务器连接

private PhotonPeer peer;

 

    private ConnectionProtocol protocol = ConnectionProtocol.Udp;//默认使用udp协议

    private string serverAddress = "127.0.0.1:5055";//连接本机ip,端口5055

    private string applicationName = "ChatRoom";//连接名称

    private bool connected = false;

    void Awake()

    {

        instance = this;

        peer = new PhotonPeer(this, protocol);

        peer.Connect(serverAddress, applicationName);//与服务器做连接

 

    }

   

void Update () {

 

        if(!connected) //如果与服务器断开了,就需要再连接一下

            peer.Connect(serverAddress, applicationName);

 

        peer.Service();//获取服务器的响应,需要每时每刻都获取,保持连接状态

 

      //这里为调试代码,当客户端按下空格是,想服务器发起请求,内容为"wowowowow"

        if (Input.GetKeyDown(KeyCode.Space))

        {

            var parameter = new Dictionary<byte, object>();

            parameter.Add(0, "wowowowow");

            peer.OpCustom(1, parameter, true);

          

        }

 

}

//停止客户端时,与服务器断开连接

     void OnDestroy()

    {

        peer.Disconnect();

}

 

 

    public void DebugReturn(DebugLevel level, string message)

    {

        

    }

 

    public void OnEvent(EventData eventData)

    {

       

    }

 

    //服务器给客户端的响应

    public void OnOperationResponse(OperationResponse operationResponse)

    {

 

     

    }

   

    //状态改变时调用

    public void OnStatusChanged(StatusCode statusCode)

    {

        Debug.Log(statusCode.ToString());

        switch (statusCode)

        {

            case StatusCode.Connect:

                connected = true;

                break;

            case StatusCode.Disconnect:

                connected = false;

                break;

        }

      

    }

}

 

 

三、连接服务器

写好客户端,就可以启动服务器,调试了,按照上面的方法启动搭建好的服务器,然后运行客户端,然后就会发现unity的控制台中的输出信息,如果是connected,表示连接成功了!

 

 

 

  回到服务器中,打开写好的输出日志

 

 

 

 

就会看到输出的调试信息 Setup ok

客户端上线

然后在客户端敲下空格,就会看到有,客户端发起请求的消息出现。

 

四、总结  

    好久没有写技术博客了,这次写发现写的并不是那么顺手,写好有点像教程一样,希望这篇博客可以帮助读者快速上手photon Server。如果有什么写得不好的地方希望可以和我探讨一下,文中有很多基本的方法没有解释到,有兴趣的也可以到官方中去查找一些文档,里面有很详细的介绍哦。

 

posted @ 2017-02-10 18:59  赵老  阅读(4750)  评论(0编辑  收藏  举报