6-5 Sending Request And Response
今天要來講解從Unity的Client端發送Request後,由Photon Server接收並傳送Response,再由Unity處理Response的訊息。這樣說明可能太複雜了,舉個比較簡單的實例來解釋:
1. Unity要求登入遊戲(發送Request,可能包含玩家的帳號密碼)
2. Photon接收登入資料(處理Request,向資料庫確認帳號密碼是否正確)
3. Photon告知登入資料正確(發送Response)
4. Unity成功讓玩家登入遊戲(處理Response)
所以大致上就是四個主要流程,發送跟處理,發出請求就叫做Request,回應請求就叫做Response。
首先,我們要在Unity中引入Photon的dll檔,從我們的lib資料夾中找到Photon3Unity3D.dll。
然後放進Plugin資料夾中,此為Unity預設用來放置第三方dll檔案的資料夾,名稱務必使用Plugin。我的習慣是先以功能分類,再依用途分類,所以我的資料夾階層是Network/Plugin。
接著在Network底下新增兩個Script,名為PhotonEngine用來建立連線的主類別,以及PhotonTest用來發出需求的類別。
接著在場景建立一個Empty GameObject,名為PhotonEngine。
開始撰寫程式碼,以下就一些重點的部分講解即可,我還會再提供原始碼跟詳細註解。因為剛剛有將dll檔放在Plugin資料夾內,所以就可以用using ExitGames.Client.Photon。
於peer.Connect的參數中要確認的有Application Name跟連接的Port Number。可以從Server上面的PhotonServer.config確認。
PhotonEngine寫好以後,再來撰寫PhotonTest,主要功能是當使用者按下滑鼠左鍵後會發送Request給Server。從PhotonEngine取得Peer以後再呼叫OpCustom即可。程式中定義了一個整數常數,為OperationCode,不管是Client端還是Server端,都是依照這個OperationCode來判斷不同的操作動作。
再來回到Server端撰寫接收Request的部分,這邊用switch判斷OperationCode為何,再進行相應的反應。Server端的OnOperationRequest方法於MyClientPeer.cs中,如有人不清楚,請先參考以前的文章唷:
6-2 Create A Photon Server Project And Import Library
接著我們向Client端發送Response,告知Client端相關資訊,比方說是否註冊成功之類的訊息。
以下提供Client端原始碼:
PhotonEngine.cs:
PhotonTest.cs:
以下提供Server端原始碼:
NoliahFantasyServer.cs:
MyClientPeer.cs:
大家應該會發現程式碼中的很多地方零碎地宣告了SIGNUP這個OperationCode,以後重構的時候會再進行調整。Server端的程式碼改好以後,記得重新Build並上傳到Server上,然後在Photon控制中心重新啟動NoliahFantasyServer。
接著來測試吧,在空白的場景中點擊滑鼠左鍵。
讓我們看看Server上的Log檔,確實有收到Request。
然後Unity上面也有收到來自Server的Response。
1. Unity要求登入遊戲(發送Request,可能包含玩家的帳號密碼)
2. Photon接收登入資料(處理Request,向資料庫確認帳號密碼是否正確)
3. Photon告知登入資料正確(發送Response)
4. Unity成功讓玩家登入遊戲(處理Response)
所以大致上就是四個主要流程,發送跟處理,發出請求就叫做Request,回應請求就叫做Response。
首先,我們要在Unity中引入Photon的dll檔,從我們的lib資料夾中找到Photon3Unity3D.dll。
然後放進Plugin資料夾中,此為Unity預設用來放置第三方dll檔案的資料夾,名稱務必使用Plugin。我的習慣是先以功能分類,再依用途分類,所以我的資料夾階層是Network/Plugin。
接著在Network底下新增兩個Script,名為PhotonEngine用來建立連線的主類別,以及PhotonTest用來發出需求的類別。
接著在場景建立一個Empty GameObject,名為PhotonEngine。
放入兩個Script。
接著使用PhotonPeer物件建立連線,由於Photon有提供Reliable UDP,解決了傳統UDP容易掉封包的問題,且速度也比TCP快很多。一般情況下建議大家採用UDP,並可依照情境自己決定是否開啟Reliable功能。除非如WebSocket這類情形原本就僅有TCP可用。
PhotonEngine寫好以後,再來撰寫PhotonTest,主要功能是當使用者按下滑鼠左鍵後會發送Request給Server。從PhotonEngine取得Peer以後再呼叫OpCustom即可。程式中定義了一個整數常數,為OperationCode,不管是Client端還是Server端,都是依照這個OperationCode來判斷不同的操作動作。
再來回到Server端撰寫接收Request的部分,這邊用switch判斷OperationCode為何,再進行相應的反應。Server端的OnOperationRequest方法於MyClientPeer.cs中,如有人不清楚,請先參考以前的文章唷:
6-2 Create A Photon Server Project And Import Library
接著我們向Client端發送Response,告知Client端相關資訊,比方說是否註冊成功之類的訊息。
以下提供Client端原始碼:
PhotonEngine.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ExitGames.Client.Photon;
public class PhotonEngine : MonoBehaviour, IPhotonPeerListener {
const int SIGNUP = 1;
PhotonPeer peer;
public static PhotonEngine Instance;
void Awake() {
if (Instance == null) {
Instance = this;
} else if (Instance != this) {
Destroy (gameObject);
return;
}
}
void Start () {
// 透過Listener回應伺服器的Response
peer = new PhotonPeer (this, ConnectionProtocol.Udp);
peer.Connect ("anoneko.cloudapp.net:5055", "NoliahFantasyServer");
}
void Update () {
// 必須在Update一直呼叫Service方法才能持續連線到Photon
peer.Service ();
}
void OnDestroy(){
if (peer != null && peer.PeerState == PeerStateValue.Connected) {
peer.Disconnect ();
}
}
public PhotonPeer GetPeer(){
return peer;
}
#region IPhotonPeerListener implementation
public void DebugReturn (DebugLevel level, string message)
{
}
// 接收由Server端傳回的Response
public void OnOperationResponse (OperationResponse operationResponse)
{
switch (operationResponse.OperationCode) {
case SIGNUP:
Debug.Log ("收到Server端的Response");
break;
}
}
public void OnStatusChanged (StatusCode statusCode)
{
}
public void OnEvent (EventData eventData)
{
}
#endregion
}
PhotonTest.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PhotonTest : MonoBehaviour {
const int SIGHUP = 1;
void Update () {
if (Input.GetMouseButtonDown (0)) {
SendRequest ();
}
}
void SendRequest(){
Dictionary data = new Dictionary ();
// 向Server發出Request,SIGNUP為整數型態的操作代碼,data為傳送的資料,true代表建立可靠連接
PhotonEngine.Instance.GetPeer().OpCustom(SIGHUP, data, true);
}
}
以下提供Server端原始碼:
NoliahFantasyServer.cs:
using System;
using System.IO;
using Photon.SocketServer;
using ExitGames.Logging;
using ExitGames.Logging.Log4Net;
using log4net.Config;
namespace NoliahFantasyServer
{
public class NoliahFantasyServer : ApplicationBase
{
public static readonly ILogger logger = LogManager.GetCurrentClassLogger();
public NoliahFantasyServer()
{
}
// 當Client端發出Request的時候
protected override PeerBase CreatePeer(InitRequest initRequest)
{
return new MyClientPeer(initRequest);
}
// Server端啟動的時候初始化
protected override void Setup()
{
LoggerInit();
}
// Server端關閉的時候
protected override void TearDown()
{
}
void LoggerInit()
{
// 日誌初始化
log4net.GlobalContext.Properties["Photon:ApplicationLogPath"] =
Path.Combine(this.ApplicationRootPath, "bin_Win64", "log");
FileInfo loggerConfig = new FileInfo(Path.Combine(this.BinaryPath, "log4net.config"));
if (loggerConfig.Exists)
{
// 設置使用log4net的Log功能
LogManager.SetLoggerFactory(Log4NetLoggerFactory.Instance);
// 讓log4net讀取config
XmlConfigurator.ConfigureAndWatch(loggerConfig);
}
logger.Info("Setup Log4Net Compeleted!");
}
}
}
MyClientPeer.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using Photon.SocketServer;
using PhotonHostRuntimeInterfaces;
namespace NoliahFantasyServer
{
public class MyClientPeer : ClientPeer
{
const int SIGNUP = 1;
public MyClientPeer(InitRequest initRequest) : base(initRequest)
{
}
// Client端斷開連結的時候
protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail)
{
}
// 處理Client的Request請求
protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
switch (operationRequest.OperationCode){
case SIGNUP:
NoliahFantasyServer.logger.Info("收到Client端的Request");
// Response物件包含OpercationCode與資料
Dictionary data = new Dictionary();
OperationResponse response = new OperationResponse(SIGNUP, data);
// 發送Response,並沿用Client端的sendParameters屬性
SendOperationResponse(response, sendParameters);
break;
}
}
}
}
大家應該會發現程式碼中的很多地方零碎地宣告了SIGNUP這個OperationCode,以後重構的時候會再進行調整。Server端的程式碼改好以後,記得重新Build並上傳到Server上,然後在Photon控制中心重新啟動NoliahFantasyServer。
接著來測試吧,在空白的場景中點擊滑鼠左鍵。
讓我們看看Server上的Log檔,確實有收到Request。
然後Unity上面也有收到來自Server的Response。
















留言
張貼留言