PhotonServer的使用

1. 服务器端初期配置与测试

1. 1 配置环境

        在photonserver官网(https://doc.photonengine.com)下载SDK,解压后放于一个英文目录,会得到 如下文件,并注册账户,然后下载Photon server Licenses,100ccu免费,然后将证书文件放于deploy\bin_Win64目录,


deploy目录中deploy\bin_Win64下的PhotonControl文件是启动photonserver的,启动后如图;


        用vs新建项目,项目类型为类库,即dll文件,因为photonserver会加载dll文件,工程引用所需dll,有三个,在lib文件夹下,分别为ExitGamesLibs,Photon.SocketServer,PhotonHostRuntimeInterfaces;

        在deploy目录下新建MyGameServer文件夹,再建bin目录,用于存放工程的生成文件,打开工程属性,将生成目录设置为deploy/MyGameServer/bin;推荐使用目标框架为.NET Framework 4.5;准备工作完成。



1.2 Server的启动

        新建类MyGameServer.cs,为主类,继承自ApplicationBase;再新建一个ClientPeer类,进行连接后的处理,继承自Photon.SocketServer.ClientPeer。

1.2.1 ClientPeer.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Photon.SocketServer;
using PhotonHostRuntimeInterfaces;

namespace MyGameServer
{
    public class ClientPeer : Photon.SocketServer.ClientPeer
    {
        public ClientPeer(InitRequest initRequest) : base(initRequest)
        {

        }

        /// <summary>
        /// 处理断开连接的处理工作
        /// </summary>
        /// <param name="reasonCode"></param>
        /// <param name="reasonDetail"></param>
        protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail)
        {
            
        }

        /// <summary>
        /// 处理客户端的请求
        /// </summary>
        /// <param name="operationRequest"></param>
        /// <param name="sendParameters"></param>
        protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
        {
            
        }
    }
}

1.2.2 MyGameServer.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Photon.SocketServer;

namespace MyGameServer
{
    //所有的server端,主类都要继承自ApplicationBase
    public class MyGameServer : ApplicationBase
    {
        //当一个客户端请求连接时调用
        //使用peerbase表示和一个客户端的连接
        protected override PeerBase CreatePeer(InitRequest initRequest)
        {
            return new ClientPeer(initRequest);
        }

        /// <summary>
        /// server启动后就调用,初始化
        /// </summary>
        protected override void Setup()
        {
            
        }

        /// <summary>
        /// server端关闭时
        /// </summary>
        protected override void TearDown()
        {
            
        }
    }
}

1.3. PhotonServer.config的配置

        需要在PhotonServer.config文件中配置自己的Application,文件中已经有一个LoadBalancing的配置和MMoDemo的配置,Application格式都差别不大,复制MMoDemo将MMoDemo标签更改为MyGameInstance,具体修改如下。

<?xml version="1.0" encoding="Windows-1252"?>
<!--
	(c) 2015 by Exit Games GmbH, http://www.exitgames.com
	Photon server configuration file.
	For details see the photon-config.pdf.

	This file contains two configurations:
		
		"LoadBalancing"
				Loadbalanced setup for local development: A Master-server and a game-server.
				Starts the apps: Game, Master, CounterPublisher
				Listens: udp-port 5055, tcp-port: 4530, 843 and 943		
	
-->

<Configuration>
	<!-- Multiple instances are supported. Each instance has its own node in the config file. -->
    
	<LoadBalancing
		MaxMessageSize="512000"
		MaxQueuedDataPerPeer="512000"
		PerPeerMaxReliableDataInTransit="51200"
		PerPeerTransmitRateLimitKBSec="256"
		PerPeerTransmitRatePeriodMilliseconds="200"
		MinimumTimeout="5000"
		MaximumTimeout="30000"
		DisplayName="LoadBalancing (MyCloud)">

		<!-- 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="Master">
			</UDPListener>
			<UDPListener
				IPAddress="0.0.0.0"
				Port="5056"
				OverrideApplication="Game">
			</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="Master"
				PolicyFile="Policy\assets\socket-policy.xml"
				InactivityTimeout="10000"
				>
			</TCPListener>
			
			<TCPListener
				IPAddress="0.0.0.0"
				Port="4531"
				OverrideApplication="Game"
				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>

		
		<!-- WebSocket (and Flash-Fallback) compatible listener -->
		<WebSocketListeners>
			<WebSocketListener
				IPAddress="0.0.0.0"
				Port="9090"
				DisableNagle="true"
				InactivityTimeout="10000"
				OverrideApplication="Master">
			</WebSocketListener>
			
			<WebSocketListener
				IPAddress="0.0.0.0"
				Port="9091"
				DisableNagle="true"
				InactivityTimeout="10000"
				OverrideApplication="Game">
			</WebSocketListener>
			
		</WebSocketListeners>

		<!-- 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="Master">		
			<Application
				Name="Master"
				BaseDirectory="LoadBalancing\Master"
				Assembly="Photon.LoadBalancing"
				Type="Photon.LoadBalancing.MasterServer.MasterApplication"
				ForceAutoRestart="true"
				WatchFiles="dll;config"
				ExcludeFiles="log4net.config"
				>
			</Application>
			<Application
				Name="Game"
				BaseDirectory="LoadBalancing\GameServer"
				Assembly="Photon.LoadBalancing"
				Type="Photon.LoadBalancing.GameServer.GameApplication"
				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>
	</LoadBalancing>	
	
	
	
	<!-- Instance settings -->
	<MMoDemo
		MaxMessageSize="512000"
		MaxQueuedDataPerPeer="512000"
		PerPeerMaxReliableDataInTransit="51200"
		PerPeerTransmitRateLimitKBSec="256"
		PerPeerTransmitRatePeriodMilliseconds="200"
		MinimumTimeout="5000"
		MaximumTimeout="30000"
		DisplayName="MMO Demo"
		>
		
		<!-- 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="MMoDemo">
			</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="MMoDemo"				
				>
			</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"
			InactivityTimeout="10000">
		  </PolicyFileListener>
		  <PolicyFileListener
			IPAddress="0.0.0.0"
			Port="943"
			PolicyFile="Policy\assets\socket-policy-silverlight.xml"
			InactivityTimeout="10000">
		  </PolicyFileListener>
		</PolicyFileListeners>

		<!-- WebSocket (and Flash-Fallback) compatible listener -->
		<WebSocketListeners>
			<WebSocketListener
				IPAddress="0.0.0.0"
				Port="9090"
				DisableNagle="true"
				InactivityTimeout="10000"
				OverrideApplication="MMoDemo">
			</WebSocketListener>
		</WebSocketListeners>

		<!-- 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="MMoDemo">
		
			<!-- MMO Demo Application -->
			<Application
				Name="MMoDemo"
				BaseDirectory="MmoDemo"
				Assembly="Photon.MmoDemo.Server"
				Type="Photon.MmoDemo.Server.PhotonApplication"
				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>
	</MMoDemo>

  <!--MyGameInstance为修改的名字,DisplayName为PhotonServer下显示的名字,其他默认-->
  <MyGameInstance
		MaxMessageSize="512000"
		MaxQueuedDataPerPeer="512000"
		PerPeerMaxReliableDataInTransit="51200"
		PerPeerTransmitRateLimitKBSec="256"
		PerPeerTransmitRatePeriodMilliseconds="200"
		MinimumTimeout="5000"
		MaximumTimeout="30000"
		DisplayName="My Game"
		>

    <!-- 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. -->
    <!--OverrideApplication修改为自定义的,其他默认-->
    <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) -->
    <!--OverrideApplication修改为自定义的,其他默认-->
    <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">

      <!-- MyGame Application -->
      <!--Name修改自定义,BaseDirectory为自己程序集所在目录,BaseDirectory="MyGameServer表示
      在deploy目录的MyGameServer目录下;Assembly为程序集名字,Type为程序集中主类;
      其他默认-->
      <Application
				Name="MyGame1"
				BaseDirectory="MyGameServer"
				Assembly="MyGameServer"
				Type="MyGameServer.MyGameServer"
				ForceAutoRestart="true"
				WatchFiles="dll;config"
				ExcludeFiles="log4net.config">
      </Application>
      
    </Applications>
  </MyGameInstance>

</Configuration>

1.4. 日志的配置与输出

        再引入日志所需库,也在lib文件夹下,分别为ExitGames.Logging.Log4Net,log4net;还需要一个日志的配置文件,可以自己写也可以拷贝提供的Demo中日志配置文件做修改;在此就拷贝src-server\Mmo\Photon.MmoDemo.Server下的log4net.config文件到本工程的根目录,并设置文件属性“复制到输出目录”为始终复制,


将日志配置文件修改<filetype="log4net.Util.PatternString"value="%property{Photon:ApplicationLogPath}\\MyGame.Server.log" />,其中只修改了日志文件名字,即MyGame,其他暂为默认。整个文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<log4net debug="false" update="Overwrite">

  <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
    <file type="log4net.Util.PatternString" value="%property{Photon:ApplicationLogPath}\\MyGame.Server.log" />
    <appendToFile value="true" />
    <maximumFileSize value="5000KB" />
    <maxSizeRollBackups value="2" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%d [%t] %-5p %c - %m%n" />
    </layout>
  </appender>

  <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
    </layout>
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="DEBUG" />
      <levelMax value="FATAL" />
    </filter>
  </appender>

  <!-- logger -->
  <root>
    <level value="INFO" />
    <!--<appender-ref ref="ConsoleAppender" />-->
    <appender-ref ref="RollingFileAppender" />
  </root>

  <logger name="OperationData">
    <level value="INFO" />
  </logger>

</log4net>

        然后再在主类MyGameServer中做日志的初始化和配置。最后如下

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ExitGames.Logging;
using ExitGames.Logging.Log4Net;
using log4net.Config;
using Photon.SocketServer;

namespace MyGameServer
{
    //所有的server端,主类都要继承自ApplicationBase
    public class MyGameServer : ApplicationBase
    {
        private static readonly ILogger log = LogManager.GetCurrentClassLogger();//日志

        //当一个客户端请求连接时调用
        //使用peerbase表示和一个客户端的连接
        protected override PeerBase CreatePeer(InitRequest initRequest)
        {
            log.Info("一个客户端连接进来了.................");
            return new ClientPeer(initRequest);
        }

        /// <summary>
        /// server启动后就调用,初始化
        /// </summary>
        protected override void Setup()
        {
            //日志的初始化
            log4net.GlobalContext.Properties["Photon:ApplicationLogPath"]=Path.Combine(
                                                                                        Path.Combine( this.ApplicationRootPath,"bin_Win64"),"log");//设置日志输出路径
            FileInfo configFileInfo = new FileInfo(Path.Combine(this.BinaryPath, "log4net.config")); //BinaryPath为工程的bin目录
            if (configFileInfo.Exists)
            {
                LogManager.SetLoggerFactory(Log4NetLoggerFactory.Instance);//让photon知道使用哪个日志插件
                XmlConfigurator.ConfigureAndWatch(configFileInfo);//让log4net这个插件读取配置文件
            }

            log.Info("Setup Completed!");
        }

        /// <summary>
        /// server端关闭时
        /// </summary>
        protected override void TearDown()
        {
            log.Info("服务器应用关闭了");
        }
    }
}

        之后如要打印日志就可直接使用log对象进行各种日志的输出。

            最后生成工程,然后deploy/MyGameServer/bin文件如下:


          然后就可打开eploy\bin_Win64下PhotonControl文件,然后启动MyGame应用,日志文件会生成在deploy\bin_Win64\log下。

2. 客户端

        新建unity工程,在建文件夹Plugins将\lib文件夹的Photon3Unity3D放于unity工程的Plugins文件夹下。

        Server与Client“交流有三种方式”,当客户端向服务器发送请求用Peer.OpCustom()方法,服务器端会受到请求在OnOperationRequest中处理,然后用SendOperationResponse再回应请求(SendOperationResponse只能在OnOperationRequest中调用),而客户端又会在OnOperationResponse()中处理服务器端回应的请求;而服务器端还可以主动向客户端发送事件,不论在什么时候都可以发送事件Event,用SendEvent发送事件,客户端接收到事件后在OnEvent()中处理。整个过程如下:


2.1 连接服务器(PhotonEngine.cs)

        继承自IPhotonPeerListener,挂载到场景中。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ExitGames.Client.Photon;

public class PhotonEngine : MonoBehaviour,IPhotonPeerListener {

    private static PhotonEngine Instance;
    private static PhotonPeer peer;

    public static PhotonPeer Peer
    {
        get
        {
            return peer;
        }
    }
    void Awake()
    {
        if(Instance==null)
        {
            Instance = this;
            DontDestroyOnLoad(this.gameObject);
        }
        else if(Instance!=this)//若跳转到其他场景,删除多余的PhotonEngine
        {
            Destroy(this.gameObject);
            return;
        }
    }
    // Use this for initialization
    void Start () {
        //通过Listender接收服务器端的响应
        peer = new PhotonPeer(this, ConnectionProtocol.Udp);
        peer.Connect("127.0.0.1:5055", "MyGame1");//连接服务器,指定IP的端口号,第二个参数为应用名
	}

    // Update is called once per frame
    void Update()
    {
         peer.Service();//需要一直调用
       
    }

    /// <summary>
    /// 游戏停止或者关闭时,要断开连接
    /// </summary>
    void OnDestroy()
    {
        if(peer!=null&&peer.PeerState==PeerStateValue.Disconnected)
        {
            peer.Disconnect();
        }
    }

    public void DebugReturn(DebugLevel level, string message)
    {
        
    }

    public void OnEvent(EventData eventData)
    {
        switch(eventData.Code)
        {
            case 1:
                Debug.Log("收到服务器发送过来的事件:"+ eventData.Code);

                //**************/解析收到的服务器端的数据****************
                Dictionary<byte, object> dataFromServer = eventData.Parameters;
                object intValue, stringValue;
                dataFromServer.TryGetValue(1, out intValue);
                dataFromServer.TryGetValue(2, out stringValue);

                Debug.Log(intValue.ToString() + " " + stringValue.ToString());
                //**************/解析收到的服务器端的数据****************
                break;
        }
    }

    public void OnOperationResponse(OperationResponse operationResponse)
    {
        switch(operationResponse.OperationCode)
        {
            case 1:
                Debug.Log("收到了服务器响应:" + operationResponse.OperationCode);
                //**************/解析收到的服务器端的数据****************
                Dictionary<byte, object> dataFromServer = operationResponse.Parameters;
                object intValue, stringValue;
                dataFromServer.TryGetValue(1, out intValue);
                dataFromServer.TryGetValue(2, out stringValue);

                Debug.Log(intValue.ToString() + " " + stringValue.ToString());
                //**************/解析收到的服务器端的数据****************

                break;
            case 2:
                break;
            default:
                break;
        }
    }

    public void OnStatusChanged(StatusCode statusCode)
    {
        Debug.Log(statusCode);
    }

}
2.2 测试连接服务器(Test.cs)

        挂载到场景中,按下鼠标左键会打印信息。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		if(Input.GetMouseButtonDown(0))
        {
            SendRequest();
        }
	}
    void SendRequest()
    {
        Dictionary<byte, object> data = new Dictionary<byte, object>();

        data.Add(1, 45);
        data.Add(2, "这是给服务器的数据");

        PhotonEngine.Peer.OpCustom(1, data, true);
    }
}

2.3 服务器端的请求处理、发送、事件(ClientPeer.cs)

        服务器端的处理都封装在了ClientPeer中,所以修改仍是对此修改。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Photon.SocketServer;
using PhotonHostRuntimeInterfaces;

namespace MyGameServer
{
    public class ClientPeer : Photon.SocketServer.ClientPeer
    {
        public ClientPeer(InitRequest initRequest) : base(initRequest)
        {

        }

        /// <summary>
        /// 处理断开连接的处理工作
        /// </summary>
        /// <param name="reasonCode"></param>
        /// <param name="reasonDetail"></param>
        protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail)
        {
            
        }

        /// <summary>
        /// 处理客户端的请求
        /// </summary>
        /// <param name="operationRequest"></param>
        /// <param name="sendParameters"></param>
        protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
        {
            switch (operationRequest.OperationCode)//通过OPCode区分请求
            {
                case 1:
                    MyGameServer.log.Info("收到了一个客户端请求");

                    //**************/解析收到的客户端数据****************
                    Dictionary<byte, object> dataFromClient = operationRequest.Parameters;
                    object intValue, stringValue;
                    dataFromClient.TryGetValue(1, out intValue);
                    dataFromClient.TryGetValue(2, out stringValue);

                    MyGameServer.log.Info("得到的参数数据是:" + intValue.ToString() + "  " + stringValue.ToString());
                    //**************/解析收到的客户端数据****************

                    //**************/发送给客户端数据****************
                    OperationResponse opResponse = new OperationResponse(1);

                    Dictionary<byte, object> dataToClient = new Dictionary<byte, object>();
                    dataToClient.Add(1, 99);
                    dataToClient.Add(2, "这是给客户端的string数据");

                    opResponse.SetParameters(dataToClient);
                    SendOperationResponse(opResponse, sendParameters);//给客户端一个响应,SendOperationResponse只能在OnOperationRequest中调用
                    //**************/发送给客户端数据****************

                    //主动向客户端发起事件
                    EventData ed = new EventData(1);
                    ed.Parameters = dataToClient;
                    SendEvent(ed, new SendParameters()); //SendEvent可以在任何地方调用,在其他地方调用要引入ClientPeer
                    break;
                case 2:
                    break;
                default:
                    break;
            }
        }
    }
}



  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Photon Server 是一种用于实时多人游戏和应用程序的实时通信解决方案,旨在提供稳定、可靠且高效的通讯网络。它采用了客户端-服务器架构,由客户端和服务器之间的交互来实现实时通信。 Photon Server 通过使用 Photon Realtime SDK 提供了跨平台的客户端库,使开发人员能够在各种设备和操作系统上创建多人游戏和应用程序。它支持多种编程语言,如C++、C#和JavaScript,使开发人员能够根据自己的喜好和经验选择合适的编程语言。 Photon Server 使用可扩展的云基础设施来处理大量的并发连接和数据传输。它具有灵活的服务器配置,使开发人员能够按照自己的需求来分配资源和管理服务器。同时,它提供了令牌验证和防止作弊的机制,确保通信的安全性和公平性。 在使用 Photon Server 进行通讯时,开发人员可以利用其提供的API来处理客户端和服务器之间的消息交换。这些消息可以是玩家输入、游戏事件或其他自定义信息。开发人员可以定义自己的逻辑和规则,并使用 Photon Server 提供的功能来同步游戏状态、处理用户之间的交互以及实现多人游戏的功能。 总而言之,Photon Server 是一个功能强大的实时通信解决方案,为开发人员提供了一种简单、灵活且可靠的方法来实现跨平台的多人游戏和应用程序。无论是小型团队开发的独立游戏,还是大型公司开发的在线多人游戏,Photon Server 都能满足各种需求,并提供出色的性能和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王大匣

你的鼓励是我创作最大动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值