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_Win32和bin_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.dll、ExitGames.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。如果有什么寫得不好的地方希望可以和我探討一下,文中有很多基本的方法沒有解釋到,有興趣的也可以到官方中去查找一些文檔,里面有很詳細的介紹哦。