Photon Server By Examples 1 从头构建一个Server


Photon Server据说好用但是能找到的资料太少,网上能找到为数不多数资料当中,针对Photon Server 3的版本讲解还占了相当大的一部分,瞬间提高了门槛,让初学者感觉不知道如何下手。情况如此,只好看官方的英文文档,这几篇文章主要结合示例项目代码学习Photon Server的使用方法,翻译、记录、整理学习过程中看的文档。

这一篇主要是从头建立一个简单的Server和Client。

建立Server

首先你需要:

  1. 下载并解压Photon Server SDK。
  2. 使用Visual Studio创建一个类库项目ChatServer,我用的是VS2015.
  3. 添加ExitGamesLibs.dll, Photon.SocketServer.dll和 PhotonHostRuntimeInterfaces.dll三个Dll,它们位于Photon Server根目录的deploy\bin_Win64下面,注意系统版本。

好了,现在创建一个ChatServer类,继承自ApplicationBase。

using Photon.SocketServer;
public class ChatServer : ApplicationBase
{
    protected override PeerBase CreatePeer(InitRequest initRequest)
    {
    }
    protected override void Setup()
    {
    }
    protected override void TearDown()
    {
    }
}

创建一个ChatPeer类继承自Photon.SocketServer.ClientPeer。

using Photon.SocketServer;
using PhotonHostRuntimeInterfaces;
 
public class ChatPeer : ClientPeer
{
    public ChatPeer(InitRequest initRequest)
        : base(initRequest)
    {
    }
    protected override void OnDisconnect(DisconnectReason disconnectCode, string reasonDetail)
    {
    }
    protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
    {
    }
}

在ChatServer中的CreatePeer中返回一个ChatPeer的实例。

protected override PeerBase CreatePeer(InitRequest initRequest)
{
    return new ChatPeer(initRequest);
}

Photon Server实例启动的时候会加载编译好的ChatServer动态链接库。因此我们需要在PhotonServer.config这个配置文件中加上这个程序的定义,添加下面的代码段。

<ChatServer DisplayName="Chat Server">
<TCPListeners>
    <TCPListener
        IPAddress="0.0.0.0"
        Port="4530"
        OverrideApplication="ChatServer"
        >
    </TCPListener>
</TCPListeners>
<!-- Defines the Photon Runtime Assembly to use. -->
<Runtime
    Assembly="PhotonHostRuntime, Culture=neutral"
    Type="PhotonHostRuntime.PhotonDomainManager"
    UnhandledExceptionPolicy="Ignore">
</Runtime>
<!-- other elements -->
<Applications Default="ChatServer">
    <Application
        Name="ChatServer"
        BaseDirectory="ChatServer"
        Assembly="ChatServer"
        Type="ChatServer">
    </Application>
    <!-- any other applications -->
</Applications>
<!-- other elements -->
</ChatServer>

这个配置文件和前面的dll在同一个目录下面。如果ChatServer类有命名空间的话,注意也要加上去。上述工程编译好之后,二进制文件要放到deploy/ChatServer/bin文件夹下面。到此就做好了一个Server。启动PhotonControll程序(需要管理员权限),在任务栏中会有Photon Server的图标出现,右键单击,选择Chat Server/start as application,即可启动Server程序。

建立Client

新创建一个控制台工程,添加Photon3DotNet.dll到引用中,Client代码如下:

using System;
using System.Collections.Generic;
using ExitGames.Client.Photon;
using System.Threading;
 
public class ChatClient : IPhotonPeerListener
{
    private bool connected;
    PhotonPeer peer;
 
    public static void Main()
    {
        var client = new ChatClient();
        client.peer = new PhotonPeer(client, ConnectionProtocol.Tcp);
        // connect
        client.DebugReturn(DebugLevel.INFO, "Connecting to server at 127.0.0.1:4530 using TCP");
        client.peer.Connect("127.0.0.1:4530", "ChatServer");
        // client needs a background thread to dispatch incoming messages and send outgoing messages
        client.Run();
        while (true)
        {
            if (!client.connected) { continue; }
            // read input
            string buffer = Console.ReadLine();
            // send to server
            var parameters = new Dictionary<byte, object> { { 1, buffer } };
            client.peer.OpCustom(1, parameters, true);
        }
    }
 
    private void UpdateLoop()
    {
        while (true)
        {
            peer.Service();
        }
    }
 
    public void Run()
    {
        Thread thread = new Thread(UpdateLoop); 
        thread.IsBackground = true;
        thread.Start();
    }
 
    #region IPhotonPeerListener
 
    public void DebugReturn(DebugLevel level, string message)
    {
        Console.WriteLine(string.Format("{0}: {1}", level, message));
    }
 
    public void OnEvent(EventData eventData)
    {
        DebugReturn(DebugLevel.INFO, eventData.ToStringFull());
        if (eventData.Code == 1)
        {
            DebugReturn(DebugLevel.INFO, string.Format("Chat Message: {0}", eventData.Parameters[1]));
        }
    }
 
    public void OnMessage(object messages)
    {
        throw new NotImplementedException();
    }
 
    public void OnOperationResponse(OperationResponse operationResponse)
    {
        DebugReturn(DebugLevel.INFO, operationResponse.ToStringFull());
    }
 
    public void OnStatusChanged(StatusCode statusCode)
    {
        if (statusCode == StatusCode.Connect)
        {
            connected = true;
        }
        switch (statusCode)
        {
            case StatusCode.Connect:
                DebugReturn(DebugLevel.INFO, "Connected");
                connected = true;
                break;
            default:
                DebugReturn(DebugLevel.ERROR, statusCode.ToString());
                break;
        }
    }
 
    #endregion
}

如果现在启动server的话,client将能够建立链接,并发送文本消息。不过现在还没有服务端逻辑啊。Server端要确定收到了消息,并且能做出响应。可以在ChatPeer.OnOperationRequest函数中返回一个OperationResponse。

protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
    // send operation response (~ACK) back to peer
    var response = new OperationResponse(operationRequest.OperationCode);
    SendOperationResponse(response, sendParameters);
}

有了返回数据,客户端现在就可以打印消息了。

下面我们要做的,是接收来自其他客户端的聊天信息。我们使用发布/订阅(publish/subscribe)模式来实现。

using Photon.SocketServer;
using PhotonHostRuntimeInterfaces;
using System;

public class ChatPeer : ClientPeer
{
  public ChatPeer(InitRequest request)
    : base(request)
{
    BroadcastMessage += OnBroadcastMessage;
}

private static event Action<ChatPeer, EventData, SendParameters> BroadcastMessage;

protected override void OnDisconnect(DisconnectReason disconnectCode, string reasonDetail)
{
    BroadcastMessage -= OnBroadcastMessage;
}

protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
    if (operationRequest.OperationCode == 1) // Chat Custom Operation Code = 1
    {
        // broadcast chat custom event to other peers
        var eventData = new EventData(1) { Parameters = operationRequest.Parameters }; // Chat Custom Event Code = 1
        BroadcastMessage(this, eventData, sendParameters);
        // send operation response (~ACK) back to peer
        var response = new OperationResponse(operationRequest.OperationCode);
        SendOperationResponse(response, sendParameters);
    }
}

private void OnBroadcastMessage(ChatPeer peer, EventData eventData, SendParameters sendParameters)
{
    if (peer != this) // do not send chat custom event to peer who called the chat custom operation 
    {
        SendEvent(eventData, sendParameters);
      }
  }
}

现在可以打开两个客户端,并且能够相互收发消息了。不要忘记使用新的配置文件重新启动Photon Server。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,628评论 18 139
  • 一:LoadRunner常见问题整理1.LR 脚本为空的解决方法:1.去掉ie设置中的第三方支持取消掉2.在系统属...
    0100阅读 4,096评论 0 11
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • 对于粉丝而言,爱豆的新歌永远是第一时间就要去听的。 上班期间躲在角落里带上耳机。 上一个人刚熄灭了烟离开,伴着尼古...
    一谦阅读 312评论 0 2
  • 禅师问:你觉得是一粒金子好,还是一堆烂泥好呢? 求道者答,当然是金子啊! 禅师笑曰,假如你是一颗种子呢? 其实,换...
    王志2017阅读 198评论 0 0