Unity使用Photon Server创建一个简单聊天室
发表于2018-01-04
关于怎么使用Photon插件进行通信网上也有这方面的资料,这里就不详细给大家介绍了。说说本文的重点,如何使用Photon Server创建一个简单聊天室,并将创建聊天室要准备的事项一一列举出来,希望可以帮到大家。















MyGameServer服务器配置
工程结构

客户端、服务器规定通用操作码与数据结构
项目名、文件夹名、文件名 | 说明 |
---|---|
Common | 客户端、服务端共同需要的标准数据结构,同时生成在Unity工程的目录下,作为DLL插件,见下图补充。 |
Code | 操作码。枚举类,用来作为判断条件信息。 |
OpCode | (Operation Code)操作码。先通过判断这个操作码才会进入下面两个操作码的处理。包含两个枚举值:Account(帐号)、Chat(聊天)。 |
AccountCode | 用户子操作码。包含两个枚举值:Register(注册)和 Login(登录)。 |
RoomCode | 聊天室子操作码。包含四个枚举值: Enter(进入)、Add(新的连接)、Talk(聊天)、Leave (离开)。 |
Dto | (Data Transfer Object)数据传输对象。用来作为通信的数据结构,需要加[Serializable]特性才能被序列化传输,这里使用Json作为传输中介。 |
AccountDto | 用户信息结构。包含两个字符串:AccountName(用户名)和 Password(密码)。 |
RoomDto | 房间信息结构。包含一个列表:AccountList(用户列表)。 |
将Common生成到Unity工程目录下。方便Untiy直接调用。


传输Dto时需要转换成Json,添加LitJson插件。


服务器结构
项目名、文件夹名、文件名 | 说明 |
---|---|
MyGameServer | 服务器,分三层结构,至下而上分别是:Model、Cache、Logic。需要引用Photon的DLL,见下图补充。 |
Model | 模型层。存放基础数据结构,用户模型和房间模型。 |
AccountModel | 用户模型。包含一个整型 ID、两个字符串分别是用户名和密码。 |
RoomModel | 房间模型。包含一个整型 ID、一个字典客户端和用户模型的映射。还有查询、添加、删除用户的基本方法。 |
Cache | 缓存层。用于存放模型列表,对模型的操作等。 |
Factory | 工厂。用来获取AccountCache和RoomCache的单例。 |
AccountCache | 用户缓存。包含所有用户ID和用户模型的映射字典,还有所有在线客户端和用户模型的映射字典,以及相关注册登录的方法。 |
RoomCache | 房间缓存。包含一个房间模型,以及客户端进入离开房间的方法。 |
Logic | 逻辑层。客户端的缓存的数据 和 服务器之间逻辑处理。 |
Handler | 处理抽象类。包含两个抽象方法 OnRequest 和 OnDisconnect ,分别是处理客户端发来的请求,以及当客户端下线时的处理。还有一个发送数据到客户端的方法。 |
AccountHandler | 用户处理。继承于Handler,用户处理当客户端发来请求时的处理(注册、登录),并回复响应处理结果。 |
RoomHandler | 房间处理。继承于Handler,处理当用户进入房间、离开房间、以及用户聊天的信息处理。 |
log4net.config | log for net。从别的Photon样例工程复制过来,拿来输出自定义日志用的配置。 |
MyApplication | 整个服务器的入口。继承至ApplicationBase。当有客户端连接时调用CreatePeer,连接客户端。 |
MyClientPeer | 连接的进来的客户端。通过它接收、处理、发送客户端的信息。 |
服务器所需要添加的引用,添加在服务器工程lib目录下,从Photon的lib目录下找到下面这些DLL。

配置到Photon,便于启动服务器。


客户端结构

UI介绍
对象名 | 说明 |
---|---|
Photon Manager | 包含PhotonManager类,用于处理客户端与服务端通信的桥梁。 |
LoginPanel | 登录UI界面。两个按钮分别是登录到聊天房间,以及进入注册界面。 |
RegisterPanel | 注册UI界面。用于注册帐号。 |
ChatCanvas | 聊天UI界面。上部分分别是显示聊天内容,以及用户列表。下部分分别是聊天信息输入和发送信息。 |
客户端脚本介绍
PhotonManager
Photon客户端管理。实现了IPhotonPeerListener接口。
// // PhotonManager // private void Awake() { instance = this; //客户端单例 peer = new PhotonPeer(this, protocol); //创建客户端,协议是UDP DontDestroyOnLoad(accountReceiver); } private void Update() { if (!connected) peer.Connect(serverAddress, applicationName); //连接服务器 if(Time.time > currentTime) { peer.Service(); //获取服务,并不需要每帧获取,简单优化 currentTime += updateIntervalTime; } } private void OnDestroy() { peer.Disconnect(); //断开连接 } //向服务器发请求,参数:操作码,参数数据字典,子操作码 public void OnOperationRequest(byte opCode, Dictionary<byte, object> parameters = null, byte SubCode = 0) { //规定键'80'对应的是子操作码 parameters[80] = SubCode; peer.OpCustom(opCode, parameters, true); } //服务端发送过来的响应 public void OnOperationResponse(OperationResponse response) { Debug.Log(response.ToStringFull()); byte subCode = (byte)response.Parameters[80]; switch ((OpCode)response.OperationCode) //判断发过来操作码,做出响应。 { case OpCode.Account: accountReceiver.OnReceive(subCode, response); break; case OpCode.Room: chatRceiver.OnReceive(subCode,response); break; } }
IReceiver
接收响应接口。
interface IReceiver { //接受服务器响应,参数:子操作码,响应信息。 void OnReceive(byte subCode, OperationResponse response); }
AccountReceiver
接收操作用户登录注册的信息响应。实现 IReceiver接口。
public AccountView accountView; public void OnReceive(byte subCode, OperationResponse response) { switch ((AccountCode)subCode) { case AccountCode.Register: if (response.ReturnCode == 0) //返回码正确时 { accountView.OnHideRegisterPanel(); //关闭注册面板。 } break; case AccountCode.Login: if (response.ReturnCode == 0) //返回码正确时 { //告诉服务器可以将进入房间了 PhotonManager.Instance.OnOperationRequest((byte)OpCode.Room, new Dictionary<byte, object>(), (byte)RoomCode.Enter); } break; } }
ChatReceiver
接收操作聊天房间的信息响应。实现 IReceiver接口。
public void OnReceive(byte subCode, OperationResponse response) { switch ((RoomCode)subCode) { case RoomCode.Enter: //本人进入房间处理 if (response.ReturnCode == 0) { loginCanvas.SetActive(false); //隐藏登录面板 chatCanvas.SetActive(true); //显示聊天面板 //获取房间信息并初始化 chatView.Init(GetResponseFromJson<RoomDto>(response)); } break; case RoomCode.Add: //房间有新用户处理 chatView.AddAccount(GetResponseFromJson<AccountDto>(response)); break; case RoomCode.Talk: //房间有人说话处理 string text = response.Parameters[0].ToString(); chatView.Append(text); break; case RoomCode.Leave: //房间有人离开处理 chatView.LeaveRoom(GetResponseFromJson<AccountDto>(response)); break; default: break; } } //从获取到的Json信息中提取出Dto private Dto GetResponseFromJson<Dto>(OperationResponse response) { return JsonUtility.FromJson<Dto>(response.Parameters[0].ToString()); }
AccountView
用户登录和注册界面UI响应。
//登录和注册发送用户信息,子操作码分别是:AccountCode.Login和AccountCode.Register public void SendAccountRequest(string accountName,string password,byte subCode) { AccountDto dto = new AccountDto(); dto.AccountName = accountName; dto.Password = password; Dictionary<byte, object> parameters = new Dictionary<byte, object>(); parameters[0] = JsonUtility.ToJson(dto); PhotonManager.Instance.OnOperationRequest((byte)OpCode.Account, parameters, subCode); }
ChatView
聊天房间界面UI响应,包括一个用户名(字符串)和对应Perfab的字典。用户的进入和离开都操作这个字典。
测试结果
1.运行测试。

2.登录一个没注册的号,登录失败。

3.注册一个充满优秀品质的帐号。

4.登录该账户并发送一条惊人的信息。

5.在另一个客户端登录另一个帐号,并发送信息。

6.回到原来的客户端查看。
