Photon——An App From Scratch 一个应用程序从头开始
An App From Scratch 一个应用程序从头开始
This tutorial will try to help you understand how to build an application from scratch.(aka “Blank Server Tutorial”)
本教程将试图帮助您理解如何从头构建应用程序(又名空白服务器教程)
Build a Simple Chat Server From the Scratch In 10 Minutes
10分钟从头开始构建一个简单的聊天服务器
Hint: This tutorial is thought as a first step in understanding the basics of the main concepts in Photon Application and Peer. For most developers that at some point will use rooms we recommend to start with with an application that inherits from Lite.Application.
提示:本教程是作为理解Photon应用和Peer中的主要概念的第一步。对于大多数开发人员来说,当使用房间时,我们建议应用程序继承自Lite应用程序。
- Download and unzip the SDK
- Create a new class library project ‘ChatServer’
- Add references to ExitGamesLibs.dll, Photon.SocketServer.dll and PhotonHostRuntimeInterfaces.dll
- Create a new class ‘ChatServer’ and inherit from ‘Photon.SocketServer.ApplicationBase’:
- 下载并解压缩SDK
- 创建一个新的类库项目”ChatServer”
- 添加引用ExitGamesLibs.dll, Photon.SocketServer.dll and PhotonHostRuntimeInterfaces.dll
- 创建一个新类的ChatServer和继承 Photon.SocketServer.ApplicationBase
using
Photon.SocketServer;
public
class
ChatServer : ApplicationBase
{
protected
override
PeerBase CreatePeer(InitRequest initRequest)
{
}
protected
override
void
Setup()
{
}
protected
override
void
TearDown()
{
}
}
- Create a new class ‘ChatPeer’ and inherit from ‘Photon.SocketServer.PeerBase’:
- 创建一个新的类ChatPeer并继承自Photon.SocketServer.PeerBase
using
Photon.SocketServer;
using
PhotonHostRuntimeInterfaces;
public
class
ChatPeer : PeerBase
{
public
ChatPeer(IRpcProtocol protocol, IPhotonPeer unmanagedPeer)
:
base
(protocol, unmanagedPeer)
{
}
protected
override
void
OnDisconnect()
{
}
protected
override
void
OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
}
}
- Return a new instance of ChatPeer at ChatServer.CreatePeer:
- 在ChatServer.CreatePeer返回一个新的ChatPeer实例
protected
override
PeerBase CreatePeer(InitRequest initRequest)
{
return
new
ChatPeer(initRequest.Protocol, initRequest.PhotonPeer);
}
- The server configuration looks like this:
- 服务器配置文件如下:
<
Applications
Default
=
"ChatServer"
>
<
Application
Name
=
"ChatServer"
BaseDirectory
=
"ChatServer"
Assembly
=
"ChatServer"
Type
=
"ChatServer"
/>
</
Applications
>
This config requires that the server binaries are located under ‘deploy/ChatServer/bin’ and that class ChatServer does not belong to a namespace.
这种配置要求服务器二进制文件位于下 deploy/ChatServer/bin,这类ChatServer不属于一个名称空间。
- Create a new console project for a chat client
- Add reference to PhotoDotNet.dll to the new project
- Client code:
- 创建一个新的控制台项目作为聊天客户端
- 添加引用PhotoDotNet.dll
- 客户端代码:
using
System;
using
System.Collections.Generic;
using
System.Text;
using
ExitGames.Client.Photon;
public
class
ChatClient : IPhotonPeerListener
{
private
bool
connected;
public
static
void
Main()
{
var
client =
new
ChatClient();
var
peer =
new
PhotonPeer(client,
true
);
// connect
client.connected =
false
;
peer.Connect(
"127.0.0.1:4530"
,
"ChatServer"
);
while
(!client.connected)
{
peer.Service();
}
var
buffer =
new
StringBuilder();
while
(
true
)
{
peer.Service();
// read input
if
(Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey();
if
(key.Key != ConsoleKey.Enter)
{
// store input
buffer.Append(key.KeyChar);
}
else
{
// send to server
var
parameters =
new
Dictionary<
byte
,
object
> { { 1, buffer.ToString() } };
peer.OpCustom(1, parameters,
true
);
buffer.Length = 0;
}
}
}
}
public
void
DebugReturn(DebugLevel level,
string
message)
{
Console.WriteLine(level +
": "
+ message);
}
public
void
OnEvent(EventData eventData)
{
Console.WriteLine(
"Event: "
+ eventData.Code);
if
(eventData.Code == 1)
{
Console.WriteLine(
"Chat: "
+ eventData.Parameters[1]);
}
}
public
void
OnOperationResponse(OperationResponse operationResponse)
{
Console.WriteLine(
"Response: "
+ operationResponse.OperationCode);
}
public
void
OnStatusChanged(StatusCode statusCode)
{
if
(statusCode == StatusCode.Connect)
{
this
.connected =
true
;
}
else
{
Console.WriteLine(
"Status: "
+ statusCode);
}
}
}
- If we now start the server the client will be able to connect and to send text messages, but the server logic to process these text messages is still missing. To verify that the message was received we answer with an OperationResponse at ChatPeer.OnOperationRequest:
- 如果我们开始这服务器,客户端将可能去连接并发送文本信息,但是服务器处理这些消息仍然会有丢失。为了验证这些信息是被接收到了,我们会在ChatPeer.OnOperationRequest响应一个OperationResponse:
protected
override
void
OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
var
response =
new
OperationResponse(operationRequest.OperationCode);
this
.SendOperationResponse(response, sendParameters);
}
The chat client should now print the event code and the chat message.
这聊天客户端会打印事件代码和聊天信息
- Next thing we want to do is to receive the chat messages on other clients. We implement a publish/subscribe pattern:
- 接下来我们要做的就是在其他客户端接收聊天信息。我们实现了一个发布/订阅模式:
using
System;
using
Photon.SocketServer;
using
PhotonHostRuntimeInterfaces;
public
class
ChatPeer : PeerBase
{
private
static
readonly
object
syncRoot =
new
object
();
public
ChatPeer(IRpcProtocol protocol, IPhotonPeer unmanagedPeer)
:
base
(protocol, unmanagedPeer)
{
lock
(syncRoot)
{
BroadcastMessage +=
this
.OnBroadcastMessage;
}
}
private
static
event
Action<ChatPeer, EventData, SendParameters> BroadcastMessage;
protected
override
void
OnDisconnect()
{
lock
(syncRoot)
{
BroadcastMessage -=
this
.OnBroadcastMessage;
}
}
protected
override
void
OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
var
@
event
=
new
EventData(1) { Parameters = operationRequest.Parameters };
lock
(syncRoot)
{
BroadcastMessage(
this
, @
event
, sendParameters);
}
var
response =
new
OperationResponse(operationRequest.OperationCode);
this
.SendOperationResponse(response, sendParameters);
}
private
void
OnBroadcastMessage(ChatPeer peer, EventData @
event
, SendParameters sendParameters)
{
if
(peer !=
this
)
{
this
.SendEvent(@
event
, sendParameters);
}
}
}
If you now start two clients they should be able to exchange messages.
如果你现在开始运行2个客户端,他们可以交换信息。