Related Posts Plugin for WordPress, Blogger...

6-7 Sending Request And Response And Event With Parameters

本章要來向大家介紹如何在發送請求的時候,將資料也一併傳給Server,Server回應時又該如何回傳資料。另外,除了Request與Response以外,Server還有傳送Event的功能,亦即直接由Server推送消息給Client。

在觀看之前,如果還不知道怎麼跟Photon Server建立連接,請先看以前的文章唷:
6-1 Photon Server By Self-Hosted

6-2 Create A Photon Server Project And Import Library

6-5 Sending Request And Response 

首先,讓我們來修改Client的PhotonTest.cs,使用Dictionary傳遞資料。

再來修改Server的MyClientPeer的OnOperationRequest,藉由operationRequest.Parameters可以取得Client傳來的參數。

重點說明一下,SendEvent是由Server主動推送,所以只要在ClientPeer類別內的任何範圍,都可以直接呼叫並傳送內容給Client。SendOperationResponse,則只能在OnOperationRequest內使用才會有反應。下列範例為了方便才在Response後就呼叫Event,實際上Event是任何時候都可以呼叫,達成主動推送的功能。

傳來的參數亦是一個Dictionary物件,這邊使用TryGetValue方法取得值,因為TryGetValue內部已經實作了判斷Key是否為空的方法,並回傳boolean值,不用自己寫條件式判斷,所以非常方便。

接著在Server端傳回Response時,同樣是用Dictionary。

回到Client端,在OnOperationResponse中取得Parameters即可取得Response資料。

接著在Server實作SendEvent,寫法同樣差不多。

在Client則由OnEvent方法負責接收。

綜合以上所述,在Photon傳送參數皆統一使用Dictionary物件。想起過去自己實作Server的時候,還要自行決定資料傳送的格式如XML、JSON,然後還要將之封裝成方便的方法,想想光前置步驟就耗費不少時間了。Photon提供給我們的方法就非常簡單易用唷!

以下提供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;
 const int BROADCAST = 2;

 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");
   // 收到Server的資料
   Dictionary serverData = operationResponse.Parameters;
   object intValue;
   serverData.TryGetValue(1, out intValue);
   object stringValue;
   serverData.TryGetValue(2, out stringValue);
   print("Server端資料:" + intValue + "," + stringValue);
   break;
  }
 }

 public void OnStatusChanged (StatusCode statusCode)
 {
 }

 // 接收由Server端發送的Event事件
 public void OnEvent (EventData eventData)
 {
  switch (eventData.Code) {
  case BROADCAST:
   Debug.Log ("收到Server端的Event");
   // 收到Server的資料
   Dictionary serverData = eventData.Parameters;
   object intValue;
   serverData.TryGetValue(1, out intValue);
   object stringValue;
   serverData.TryGetValue(2, out stringValue);
   print("Server端資料:" + intValue + "," + stringValue);
   break;
  }
 }

 #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 ();
  data.Add(1, 654321);
  data.Add(2, "Client的Request資料");
  // 向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;
        const int BROADCAST = 2;
        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");
                    // 取得Client端的資料
                    ProcessData(operationRequest.Parameters);
                    // 發送Response
                    SendResponse(sendParameters);
                    // 發送Event
                    SendMyEvent(sendParameters);
                    break;
            }
        }

        void ProcessData(Dictionary clientData){
            object intValue;
            clientData.TryGetValue(1, out intValue);
            object stringValue;
            clientData.TryGetValue(2, out stringValue);
            NoliahFantasyServer.logger.Info("Client端資料:" + intValue + "," + stringValue);
        }

        void SendResponse(SendParameters sendParameters){
            // Response物件包含OpercationCode與資料
            Dictionary data = new Dictionary();
            data.Add(1, 123456);
            data.Add(2, "Server的Response資料");
            OperationResponse response = new OperationResponse(SIGNUP, data);
            // 發送Response,並沿用Client端的sendParameters屬性
            SendOperationResponse(response, sendParameters);
        }

        void SendMyEvent(SendParameters sendParameters){
            Dictionary data = new Dictionary();
            data.Add(1, 333333);
            data.Add(2, "Server的Event資料");
            EventData eventData = new EventData(BROADCAST, data);
            SendEvent(eventData, sendParameters);
        }
    }
}


撰寫完程式碼以後,來測試看看吧。從Server的Log看見接收到Client的資料了。

Client也接收到Server的Response跟Event。

留言