项目下载地址
https://gitee.com/dreamsfly900/universal-Data-Communication-System-for-windows
Example /Unity3D_2DShootServer_Client 项目文件位置。
教程编写有 SuperLinMeng 提供,QQ:2360450496
WeaveSocket通讯框架官方QQ群17375149
WeaveSocket框架-Unity太空大战游戏-
概述0
先看下最终的效果
服务端
用户登录后,认证成功进入游戏后
客户端
输入错误密码,有提示信息
主要技术架构
服务端端:
Socket框架【WeaveSocket】
https://gitee.com/dreamsfly900/universal-Data-Communication-System-for-windows/
数据库【LiteDB】(3.1.4.0)
界面UI【WPF】(.Net4.5)
项目源码图
Unity3D客户端:
WeaveSocket官方QQ群17375149
服务端运行图:
主要的用到的类为:
WeaveTCPcloud类(部分重写,与原作者源码不同,请注意下)
代码如下:
using MyTcpCommandLibrary;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Reflection;
using System.Xml;
using WeaveBase;
using WeaveSocketServer;
namespace MyTCPCloud
{
public class WeaveTCPcloud : IWeaveUniversal
{
public event WeaveLogDelegate WeaveLogEvent;
public event WeaveServerReceiveDelegate WeaveReceiveEvent;
public event WeaveServerUpdateSocketHander WeaveUpdateEvent;
public event WeaveServerDeleteSocketHander WeaveDeleteEvent;
public event WeaveServerUpdateUnityPlayerSetOnLineHander WeaveServerUpdateUnityPlayerSetOnLineEvent;
//public XmlDocument xml
//{
// get;set;
//}
public List<CmdWorkItem> CmdWorkItems
{
get
{
return _CmdWorkItems;
}
set
{
_CmdWorkItems = value;
}
}
public WeaveTable weaveTable
{
get
{
return _weaveTable;
}
set
{
_weaveTable = value;
}
}
public List<WeaveOnLine> weaveOnline
{
get
{
return _weaveOnline;
}
set
{
_weaveOnline = value;
}
}
public List<UnityPlayerOnClient> unityPlayerOnClientList
{
get
{
return _unityPlayerOnClientList;
}
set
{
_unityPlayerOnClientList = value;
}
}
// public IWeaveTcpBase P2Server
public WeaveP2Server P2Server
{
get;set;
}
public WeaveTcpToken TcpToken
{
get
{
return _TcpToken;
}
set
{
_TcpToken = value;
}
}
List<CmdWorkItem> _CmdWorkItems = new List<CmdWorkItem>();
WeaveTable _weaveTable = new WeaveTable();
List<WeaveOnLine> _weaveOnline = new List<WeaveOnLine>();
WeaveTcpToken _TcpToken = new WeaveTcpToken();
//我写的方法
List<UnityPlayerOnClient> _unityPlayerOnClientList = new List<UnityPlayerOnClient>();
public bool Run(WevaeSocketSession myI)
{
//ReloadFlies();
AddMyTcpCommandLibrary();
weaveTable.Add("onlinetoken", weaveOnline);//初始化一个队列,记录在线人员的token
if (WeaveLogEvent != null)
WeaveLogEvent("连接", "连接启动成功");
return true;
}
/// <summary>
/// 读取WeavePortTypeEnum类型后,初始化 new WeaveP2Server("127.0.0.1"),并添加端口;
/// </summary>
/// <param name="WeaveServerPort"></param>
public void StartServer(WeaveServerPort _ServerPort)
{
// WeaveTcpToken weaveTcpToken = new WeaveTcpToken();
P2Server = new WeaveP2Server("127.0.0.1");
P2Server.waveReceiveEvent += P2ServerReceiveHander;
P2Server.weaveUpdateSocketListEvent += P2ServerUpdateSocketHander;
P2Server.weaveDeleteSocketListEvent += P2ServerDeleteSocketHander;
// p2psev.NATthroughevent += tcp_NATthroughevent;//p2p事件,不需要使用
P2Server.Start( _ServerPort.Port );//myI.Parameter[4]是端口号
TcpToken.PortType = _ServerPort.PortType;
TcpToken.P2Server = P2Server;
TcpToken.IsToken = _ServerPort.IsToken;
TcpToken.WPTE = _ServerPort.PortType;
// TcpToken = weaveTcpToken;
// P2Server = p2psev;
}
public void AddMyTcpCommandLibrary()
{
try
{
LoginManageCommand loginCmd = new LoginManageCommand();
loginCmd.ServerLoginOKEvent += UpdatePlayerListSetOnLine;
AddCmdWorkItems(loginCmd);
AddCmdWorkItems(new GameScoreCommand());
AddCmdWorkItems(new ClientDisConnectedCommand());
}
catch
{
}
}
public void AddCmdWorkItems(WeaveTCPCommand cmd)
{
cmd.SetGlobalQueueTable(weaveTable, TcpToken);
CmdWorkItem cmdItem = new CmdWorkItem();
// Ic.SetGlobalQueueTable(weaveTable, TcpTokenList);
cmdItem.WeaveTcpCmd = cmd;
cmdItem.CmdName = cmd.Getcommand();
GetAttributeInfo(cmd, cmd.GetType(), cmd);
CmdWorkItems.Add(cmdItem);
}
public void GetAttributeInfo(WeaveTCPCommand Ic, Type t, object obj)
{
foreach (MethodInfo mi in t.GetMethods())
{
InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute));
if (myattribute == null)
{
}
else
{
if (myattribute.Dtu)
{
Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDtuDelegate), obj, mi, true);
Ic.Bm.AddListen(mi.Name, del as WeaveRequestDataDtuDelegate, myattribute.Type, true);
}
else
{
Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDelegate), obj, mi, true);
Ic.Bm.AddListen(mi.Name, del as WeaveRequestDataDelegate, myattribute.Type);
}
}
}
}
void P2ServerDeleteSocketHander(System.Net.Sockets.Socket soc)
{
/*我写的方法*/
WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc);
if (hasOnline != null)
{
UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline);
WeaveDeleteEvent(uplayer);
weaveOnline.Remove(hasOnline);
// unityPlayerOnClientList.Remove(uplayer);
DeleteUnityPlayerOnClient(hasOnline.Socket);
}
/**/
try
{
int count = CmdWorkItems.Count;
CmdWorkItem[] cilist = new CmdWorkItem[count];
CmdWorkItems.CopyTo(0, cilist, 0, count);
foreach (CmdWorkItem CI in cilist)
{
try
{
CI.WeaveTcpCmd.WeaveDeleteSocketEvent(soc);
}
catch (Exception ex)
{
if (WeaveLogEvent != null)
WeaveLogEvent("EventDeleteConnSoc", ex.Message);
}
}
}
catch { }
try
{
int count = weaveOnline.Count;
WeaveOnLine[] ols = new WeaveOnLine[count];
weaveOnline.CopyTo(0, ols, 0, count);
foreach (WeaveOnLine ol in ols)
{
if (ol.Socket.Equals(soc))
{
foreach (CmdWorkItem CI in CmdWorkItems)
{
try
{
WeaveExcCmdNoCheckCmdName(0xff, "out|" + ol.Token, ol.Socket);
CI.WeaveTcpCmd.Tokenout(ol);
}
catch (Exception ex)
{
if (WeaveLogEvent != null)
WeaveLogEvent("Tokenout", ex.Message);
}
}
weaveOnline.Remove(ol);
return;
}
}
}
catch { }
}
public void UpdatePlayerListSetOnLine(string _userName , System.Net.Sockets.Socket soc)
{
foreach(UnityPlayerOnClient oneclient in unityPlayerOnClientList)
{
if(oneclient.Socket == soc)
{
oneclient.UserName = _userName;
oneclient.isLogin = true;
WeaveServerUpdateUnityPlayerSetOnLineEvent(oneclient);
break;
}
}
}
void P2ServerUpdateSocketHander(System.Net.Sockets.Socket soc)
{
#region 读取 Command接口类,每次有新的Socket加入 重新读取并设置
try
{
int count = CmdWorkItems.Count;
CmdWorkItem[] cilist = new CmdWorkItem[count];
CmdWorkItems.CopyTo(0, cilist, 0, count);
foreach (CmdWorkItem CI in cilist)
{
try
{
CI.WeaveTcpCmd.WeaveUpdateSocketEvent(soc);
}
catch (Exception ex)
{
if (WeaveLogEvent != null)
WeaveLogEvent("EventUpdataConnSoc", ex.Message);
}
}
}
catch
{
}
#endregion 发送Token的代码
WeaveTcpToken token = TcpToken;
{
if (token.IsToken)
{
//生成一个token,后缀带随机数
string Token = DateTime.Now.ToString("yyyyMMddHHmmssfff") + new Random().Next(1000, 9999);// EncryptDES(clientipe.Address.ToString() + "|" + DateTime.Now.ToString(), "lllssscc");
if (token.P2Server.Port == ((System.Net.IPEndPoint)soc.LocalEndPoint).Port)
{
//向客户端发送生成的token
bool sendok = false;
if (token.PortType == WeavePortTypeEnum.Bytes)
sendok = token.P2Server.Send(soc, 0xff, token.BytesDataparsing.Get_ByteBystring("token|" + Token + ""));
else
sendok = token.P2Server.Send(soc, 0xff, "token|" + Token + "");
#region if(sendok)
if (sendok)
{
WeaveOnLine ol = new WeaveOnLine()
{
Name = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
Obj = DateTime.Now.ToString("yyyyMMddHHmmssfff")
};
ol.Token = Token;
ol.Socket = soc;
WeaveOnLine hasOnline = weaveOnline.Find(item => item.Name == ol.Name);
{
if (hasOnline != null)
{
weaveOnline.Remove(hasOnline);
weaveOnline.Add(ol);
}
else
{
weaveOnline.Add(ol);
}
}
/*我单独写的UnityClient*/
/*我写的新方法*/
UnityPlayerOnClient hasPlayerIn = unityPlayerOnClientList.Find(item => item.Name == ol.Name);
if (hasPlayerIn != null)
{
WeaveDeleteEvent(hasPlayerIn);
unityPlayerOnClientList.Remove(hasPlayerIn);
}
/*我写的方法结束*/
UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(ol);
// unityPlayerOnClientList.Add(uplayer);
AddUnityPlayerClient_CheckSameItem(uplayer , ol.Name);
WeaveUpdateEvent(uplayer);
/**/
foreach (CmdWorkItem cmdItem in CmdWorkItems)
{
try
{
WeaveExcCmdNoCheckCmdName(0xff, "in|" + ol.Token, ol.Socket);
cmdItem.WeaveTcpCmd.TokenIn(ol);
}
catch (Exception ex)
{
if (WeaveLogEvent != null)
WeaveLogEvent("Tokenin", ex.Message);
}
}
return;
}
#endregion
}
}
else
{
WeaveOnLine ol = new WeaveOnLine()
{
Name = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
Obj = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
Socket = soc,
Token = DateTime.Now.ToString("yyyyMMddHHmmssfff")
};
weaveOnline.Add(ol);
/*我单独写的UnityClient*/
UnityPlayerOnClient hasPlayerIn = unityPlayerOnClientList.Find(item => item.Socket == soc);
if (hasPlayerIn != null)
{
WeaveDeleteEvent(hasPlayerIn);
unityPlayerOnClientList.Remove(hasPlayerIn);
}
UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(ol);
AddUnityPlayerClient_CheckSameItem(uplayer, ol.Name);
WeaveUpdateEvent(uplayer);
/**/
// ol.Token = DateTime.Now.ToString();
// ol.Socket = soc;
}
}
}
void P2ServerReceiveHander(byte command, string data, System.Net.Sockets.Socket soc)
{
if(command == (byte)CommandEnum.ClientSendDisConnected)
{
P2Server.CliendSendDisConnectedEvent(soc);
/*我写的方法*/
WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc);
if (hasOnline != null)
{
UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline);
WeaveDeleteEvent(uplayer);
weaveOnline.Remove(hasOnline);
// unityPlayerOnClientList.Remove(uplayer);
DeleteUnityPlayerOnClient(hasOnline.Socket);
}
/**/
return;
}
try
{
//触发接收到信息的事件...
/*我写的方法*/
WeaveOnLine hasOnline = weaveOnline.Find(item => item.Socket == soc);
if(hasOnline != null)
{
UnityPlayerOnClient uplayer = ConvertWeaveOnlineToUnityPlayerOnClient(hasOnline);
WeaveReceiveEvent(command, data, uplayer);
}
/**/
if (command == 0xff)
{
//如果是网关command 发过来的 命名,那么执行下面的
WeaveExcCmdNoCheckCmdName(command, data, soc);
try
{
string[] temp = data.Split('|');
if (temp[0] == "in")
{
//加入onlinetoken
WeaveOnLine ol = new WeaveOnLine();
ol.Token = temp[1];
ol.Socket = soc;
weaveOnline.Add(ol);
foreach (CmdWorkItem CI in CmdWorkItems)
{
try
{
CI.WeaveTcpCmd.TokenIn(ol);
}
catch (Exception ex)
{
WeaveLogEvent?.Invoke("Tokenin", ex.Message);
}
}
return;
}
else if (temp[0] == "Restart")
{
int count = weaveOnline.Count;
WeaveOnLine[] ols = new WeaveOnLine[count];
weaveOnline.CopyTo(0, ols, 0, count);
string IPport = ((System.Net.IPEndPoint)soc.RemoteEndPoint).Address.ToString() + ":" + temp[1];
foreach (WeaveOnLine ol in ols)
{
try
{
if (ol.Socket != null)
{
String IP = ((System.Net.IPEndPoint)ol.Socket.RemoteEndPoint).Address.ToString() + ":" + ((System.Net.IPEndPoint)ol.Socket.RemoteEndPoint).Port;
if (IP == IPport)
{
ol.Socket = soc;
}
}
}
catch { }
}
}
else if (temp[0] == "out")
{
////移出onlinetoken
int count = weaveOnline.Count;
WeaveOnLine[] ols = new WeaveOnLine[count];
weaveOnline.CopyTo(0, ols, 0, count);
foreach (WeaveOnLine onlinesession in ols)
{
if (onlinesession.Token == temp[1])
{
foreach (CmdWorkItem cmdItem in CmdWorkItems)
{
try
{
cmdItem.WeaveTcpCmd.Tokenout(onlinesession);
}
catch (Exception ex)
{
WeaveLogEvent?.Invoke("Tokenout", ex.Message);
}
}
weaveOnline.Remove(onlinesession);
return;
}
}
}
}
catch { }
return;
}
else
WeaveExcCmd(command, data, soc);
}
catch
{
return;
}
//System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(exec));
}
/// <summary>
/// 网关0xff这个command发来的...命令
/// </summary>
/// <param name="command"></param>
/// <param name="data"></param>
/// <param name="soc"></param>
public void WeaveExcCmdNoCheckCmdName(byte command, string data, System.Net.Sockets.Socket soc)
{
foreach (CmdWorkItem cmd in CmdWorkItems)
{
try
{
cmd.WeaveTcpCmd.Runcommand(command, data, soc);
}
catch (Exception ex)
{
WeaveLogEvent?.Invoke("receiveevent", ex.Message);
}
}
}
/// <summary>
/// 不是0xff这个command发来的...命令
/// </summary>
/// <param name="command"></param>
/// <param name="data"></param>
/// <param name="soc"></param>
public void WeaveExcCmd(byte command, string data, System.Net.Sockets.Socket soc)
{
foreach (CmdWorkItem cmd in CmdWorkItems)
{
if (cmd.CmdName == command)
{
try
{
cmd.WeaveTcpCmd.Run(data, soc);
cmd.WeaveTcpCmd.RunBase(data, soc);
}
catch (Exception ex)
{
WeaveLogEvent?.Invoke("receiveevent", ex.Message);
}
}
}
}
public UnityPlayerOnClient ConvertWeaveOnlineToUnityPlayerOnClient(WeaveOnLine wonline)
{
UnityPlayerOnClient uplayer = new UnityPlayerOnClient()
{
Obj = wonline.Obj,
Socket = wonline.Socket,
Token = wonline.Token,
Name = wonline.Name
};
return uplayer;
}
public void DeleteUnityPlayerOnClient(Socket osc)
{
try
{
if (unityPlayerOnClientList.Count > 0)
unityPlayerOnClientList.Remove(unityPlayerOnClientList.Find(u => u.Socket == osc));
}
catch
{
}
}
public void AddUnityPlayerClient_CheckSameItem(UnityPlayerOnClient item ,string itemName)
{
System.Threading.Thread.Sleep(500);
lock (this)
{
if (unityPlayerOnClientList.Find(i => i.Name == itemName) != null)
return;
else
unityPlayerOnClientList.Add(item);
}
}
//public class CmdWorkItem
//{
// public byte CmdName
// {
// get;set;
// }
// public WeaveTCPCommand WeaveTcpCmd
// {
// get;set;
// }
//}
}
}
-----------------------------------------
重点说下AddMyTcpCommandLibrary方法
加载几个继承自 WeaveTCPCommand的类,里面写有一些方法,当服务器接收到客户端的一些参数后,可以直接跳转执行里面的写的方法,你可以新建一个类库项目(我这里命名为MyTcpCommandLibrary),然后引用项目 WeaveBase和WeaveSocketServer。在MyTcpCommandLibrary项目下新建几个类(根据你想要的逻辑),类继承WeaveTCPCommand,然后有具体的方法单独写出来,如
[InstallFun("forever")]
public void CheckLogin(Socket soc, WeaveSession wsession)
{
// string jsonstr = _0x01.Getjson();
LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>();
//执行查找数据的操作......
bool loginOk = false;
AddSystemData();
loginOk = CheckUserCanLoginIn(get_client_Send_loginModel);
if (loginOk)
{
// UpdatePlayerListSetOnLine
ServerLoginOKEvent(get_client_Send_loginModel.userName, soc);
}
SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token);
//发送人数给客户端
//参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token
}
当客户端发送命名为 Getcommand() 返回的命令byte,并且参数含方法名,即可直接调用服务端WeaveTCPCommand写的这个CheckLogin方法
客户端调用示例
weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0);
再说下前端WPF启动服务器开始监听的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WeaveBase;
using System.Net.Sockets;
using MyTCPCloud;
using System.Windows.Threading;
namespace WeavingSocketServerWPF
{
/// <summary>
/// MyUnityServer.xaml 的交互逻辑
/// </summary>
public partial class MyUnityServer : Window
{
public MyUnityServer()
{
InitializeComponent();
// DispatcherFunction();
}
/// <summary>
/// 监听端口列表,,可以选择监听多个端口
/// </summary>
WeaveServerPort wserverport = new WeaveServerPort();
WeaveTCPcloud weaveTCPcloud = new WeaveTCPcloud();
List<MyListBoxItem> loginedUserList = new List<MyListBoxItem>();
List<MyListBoxItem> connectedSocketItemList = new List<MyListBoxItem>();
// DispatcherTimer dispatcherTimer = new DispatcherTimer();
private void StartListen_button_Click(object sender, RoutedEventArgs e)
{
//设置登陆后的用户列表Listbox的数据源
LoginedUser_listBox.ItemsSource = loginedUserList;
//设置连接到服务器的Socket列表的Listbox的数据源
ConnectedSocket_listBox.ItemsSource = connectedSocketItemList;
WevaeSocketSession mif = new WevaeSocketSession();
weaveTCPcloud.Run(mif);
wserverport.IsToken = true;
wserverport.Port = Convert.ToInt32(Port_textBox.Text);
wserverport.PortType = WeavePortTypeEnum.Json;
weaveTCPcloud.StartServer(wserverport);
weaveTCPcloud.WeaveReceiveEvent += OnWeaveReceiveMessage;
weaveTCPcloud.WeaveDeleteEvent += OnWeaveDeleteSocket;
weaveTCPcloud.WeaveUpdateEvent += OnWeaveUpdateSocket;
weaveTCPcloud.WeaveServerUpdateUnityPlayerSetOnLineEvent += OnWeaveServerUpdateUnityPlayerSetOnLineEvent;
StartListen_button.Content = "正在监听";
StartListen_button.IsEnabled = false;
}
private void OnWeaveServerUpdateUnityPlayerSetOnLineEvent(UnityPlayerOnClient gamer)
{
//throw new NotImplementedException();
//当有用户 账号密码登陆成功的时候
AddListBoxItemAction(loginedUserList, CopyUnityPlayerOnClient(gamer));
SetServerReceiveText("--触发了一次(OnWeaveServerUpdateUnityPlayerSetOnLineEvent)" + Environment.NewLine);
}
private void OnWeaveUpdateSocket(UnityPlayerOnClient gamer)
{
SetServerReceiveText("--触发了一次(OnWeaveUpdateSocket)" + Environment.NewLine);
//有 Sokcet客户端连接到服务器的时候,暂未 账号,密码认证状态
AddListBoxItemAction(connectedSocketItemList, CopyUnityPlayerOnClient(gamer) );
}
private void OnWeaveDeleteSocket(UnityPlayerOnClient gamer)
{
SetServerReceiveText("--退出事件,,触发了一次(OnWeaveDeleteSocket)" + Environment.NewLine);
RemoveListBoxItemAction(connectedSocketItemList, CopyUnityPlayerOnClient(gamer));
RemoveListBoxItemAction(loginedUserList, CopyUnityPlayerOnClient(gamer));
}
private void OnWeaveReceiveMessage(byte command, string data, UnityPlayerOnClient gamer)
{
WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(data);
SetServerReceiveText("接收到新信息: " + ws.Root + Environment.NewLine );
}
private void StopListen_button_Click(object sender, RoutedEventArgs e)
{
weaveTCPcloud.P2Server = null;
weaveTCPcloud = null;
Application.Current.Shutdown();
Environment.Exit(0);// 可以立即中断程序执行并退出
}
private void SendMsg_button_Click(object sender, RoutedEventArgs e)
{
string serverMsg = InputSendMessage_textBox.Text;
int unityGamecount = weaveTCPcloud.unityPlayerOnClientList.Count;
if (string.IsNullOrEmpty(serverMsg) || weaveTCPcloud.weaveOnline.Count==0)
return;
WeaveOnLine[] _allWeaveOnLine = new WeaveOnLine[weaveTCPcloud.weaveOnline.Count];
weaveTCPcloud.weaveOnline.CopyTo(_allWeaveOnLine);
foreach (WeaveOnLine oneWeaveOnLine in _allWeaveOnLine)
{
weaveTCPcloud.P2Server.Send(oneWeaveOnLine.Socket, 0x01, "服务器主动给所有客户端发消息了: " + serverMsg);
}
// MessageBox.Show("客户端在线数量:"+ _allWeaveOnLine.Length);
}
private void UpdateServerReceiveTb(TextBlock tb, string text)
{
tb.Text += text;
}
private void SetServerReceiveText(string newtext)
{
Action<TextBlock, String> updateAction = new Action<TextBlock, string>(UpdateServerReceiveTb);
ServerReceive_textBlock.Dispatcher.BeginInvoke(updateAction, ServerReceive_textBlock, newtext);
}
public MyListBoxItem CopyUnityPlayerOnClient(UnityPlayerOnClient one)
{
MyListBoxItem item = new MyListBoxItem()
{
UIName_Id = one.Socket.RemoteEndPoint.ToString(),
ShowMsg = "UserIP:" + one.Socket.RemoteEndPoint.ToString() + " -Token:" + one.Token,
UserName = one.UserName,
Ip = one.Socket.RemoteEndPoint.ToString()
};
return item;
}
public void AddListBoxItem(List<MyListBoxItem> sList , MyListBoxItem one)
{
sList.Add(one);
CheckListBoxSource();
}
public void AddListBoxItemAction(List<MyListBoxItem> sList, MyListBoxItem one)
{
Action< List < MyListBoxItem > , MyListBoxItem> addListBoxItemAction =
new Action<List<MyListBoxItem> , MyListBoxItem>(AddListBoxItem);
this.Dispatcher.BeginInvoke(addListBoxItemAction,sList , one);
}
public void RemoveListBoxItem(List<MyListBoxItem> sList, MyListBoxItem one)
{
MyListBoxItem item = sList.Find(i=>i.Ip == one.Ip);
if(item != null)
{
sList.Remove(item);
}
CheckListBoxSource();
}
public void RemoveListBoxItemAction(List<MyListBoxItem> sList, MyListBoxItem one)
{
Action<List<MyListBoxItem>, MyListBoxItem> removeListBoxItemAction =
new Action<List<MyListBoxItem>, MyListBoxItem>(RemoveListBoxItem);
this.Dispatcher.BeginInvoke(removeListBoxItemAction, sList , one);
}
public void CheckListBoxSource()
{
//数据发生变化后,重新设置登陆后的用户列表Listbox的数据源
LoginedUser_listBox.ItemsSource = null;
LoginedUser_listBox.ItemsSource = loginedUserList;
//数据发生变化后,重新设置连接到服务器的Socket列表的Listbox的数据源
ConnectedSocket_listBox.ItemsSource = null;
ConnectedSocket_listBox.ItemsSource = connectedSocketItemList;
}
protected override void OnClosed(EventArgs e)
{
weaveTCPcloud.P2Server = null;
weaveTCPcloud = null;
//Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
//if (this.IsAfreshLogin == true) return;
Application.Current.Shutdown();
Environment.Exit(0);// 可以立即中断程序执行并退出
base.OnClosed(e);
}
}
public class MyListBoxItem
{
public string UIName_Id { get; set; }
public string Ip { get; set; }
public string ShowMsg { get; set; }
public string UserName { get; set; }
}
}
主要的启动服务器的代码为
WeaveServerPort wserverport = new WeaveServerPort();
WeaveTCPcloud weaveTCPcloud = new WeaveTCPcloud();
WevaeSocketSession mif = new WevaeSocketSession();
//不知道这里干嘛,没搞懂
weaveTCPcloud.Run(mif);
wserverport.IsToken = true;
wserverport.Port = Convert.ToInt32(Port_textBox.Text);
wserverport.PortType = WeavePortTypeEnum.Json;
weaveTCPcloud.StartServer(wserverport);
weaveTCPcloud.WeaveReceiveEvent += OnWeaveReceiveMessage;
weaveTCPcloud.WeaveDeleteEvent += OnWeaveDeleteSocket;
weaveTCPcloud.WeaveUpdateEvent += OnWeaveUpdateSocket;
weaveTCPcloud.WeaveServerUpdateUnityPlayerSetOnLineEvent += OnWeaveServerUpdateUnityPlayerSetOnLineEvent;
事件分别是
weaveTCPcloud.WeaveReceiveEvent += OnWeaveReceiveMessage;
接受到客户端发来的数据事件(这里如果发来的数据第一位byte命令跟上面的MyTcpCommandLibrary项目里面,继承自WeaveTCPCommand类,具体的返回的Getcommand()方法返回的byte命名相同,则会进入那个类进行处理)
假如客户端发送代码如下
weaveSocketGameClient.SendRoot
表示客户端发送的命名是0x02 ,数据实体类是 LoginTempModel (数据发送报文格式,我们稍后再说)
服务端 MyTcpCommandLibrary有个类有如下代码
public class LoginManageCommand : WeaveTCPCommand
{
public delegate void ServerLoginOK(string _u,Socket _s);
public event ServerLoginOK ServerLoginOKEvent;
public override byte Getcommand()
{
//此CLASS的实例,代表的指令,指令从0-254,0x9c与0xff为内部指令不能使用。
//0x01的意思是,只要是0x01的指令,都会进入本实例进行处理
//return 0x01;
return (byte)CommandEnum.ClientSendLoginModel; //0x02;
}
public override bool Run(string data, Socket soc)
{
//此事件是接收事件,data 是String类型的数据,soc是发送人。
return true;
}
public override void WeaveBaseErrorMessageEvent(Socket soc, WeaveSession _0x01, string message)
{
//错误异常事件,message为错误信息,soc为产生异常的连接
}
public override void WeaveDeleteSocketEvent(Socket soc)
{
//此事件是当有人中断了连接,此事件会被调用
}
public override void WeaveUpdateSocketEvent(Socket soc)
{
//此事件是当有人新加入了连接,此事件会被调用
}
[InstallFun("forever")]
public void CheckLogin(Socket soc, WeaveSession wsession)
{
// string jsonstr = _0x01.Getjson();
LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>();
//执行查找数据的操作......
bool loginOk = false;
AddSystemData();
loginOk = CheckUserCanLoginIn(get_client_Send_loginModel);
if (loginOk)
{
// UpdatePlayerListSetOnLine
ServerLoginOKEvent(get_client_Send_loginModel.userName, soc);
}
SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token);
//发送人数给客户端
//参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token
}
private void AddSystemData()
{
GameDataAccess.BLL.UserTableBLL myBLL = new GameDataAccess.BLL.UserTableBLL();
if( myBLL.CheckDataBaseIsNull())
{
myBLL.AddTestData();
}
}
private bool CheckUserCanLoginIn(LoginTempModel m)
{
GameDataAccess.BLL.UserTableBLL myBLL = new GameDataAccess.BLL.UserTableBLL();
return myBLL.CheckUserNamePassword(m.userName, m.password);
}
}
那么则会调用服务端的CheckLogin方法
weaveTCPcloud.WeaveDeleteEvent += OnWeaveDeleteSocket;
当有Socket连接断开的事件
weaveTCPcloud.WeaveUpdateEvent += OnWeaveUpdateSocket;
当有新的Socket连接-首次连接成功的事件
weaveTCPcloud.WeaveServerUpdateUnityPlayerSetOnLineEvent += OnWeaveServerUpdateUnityPlayerSetOnLineEvent;
这是我根据源码修改的一个事件,当客户端连接成功,并且发送账号密码到服务器,服务器查找数据库后,确认给客户端可以登陆游戏后,把当前用户设置为已经上线的游戏玩家的事件
数据格式如下图
发送数据的主要代码为
byte[] sendb = System.Text.Encoding.UTF8.GetBytes(text);
byte[] part3_length = System.Text.Encoding.UTF8.GetBytes(sendb.Length.ToString());
byte[] b = new byte[2 + part3_length.Length + sendb.Length];
b[0] = command; //表示第一位byte的命令
b[1] = (byte)part3_length.Length; //表示第三部分数据的长度
part3_length.CopyTo(b, 2);
//扩充 第四部分数据(待发送的数据)的长度,扩充到b数组第三位开始的后面
sendb.CopyTo(b, 2 + part3_length.Length);
//扩充 第四部分数据实际的数据,扩充到b数组第三部分结尾后面...
socket.Send( b );
客户端代码结构
登陆界面
游戏场景
-------------------------------------
主要的逻辑流程
----------------------------------------------
启动程序
----------------------------------------------
玩家输入账号密码
----------------------------------------------
点击登陆按钮
----------------------------------------------
连接服务器(如果成功),继续发送账号密码到服务器的命令
----------------------------------------------
服务器接收账号密码,进行查找数据库操作
----------------------------------------------
发送查找结果给客户端......
----------------------------------------------
如果客户端接收到服务器发过来的登陆成功消息(跳转到游戏场景),
----------------------------------------------
如果返回失败,那么提示账号密码错误
----------------------------------------------
客户端再次发送查找当前用户的历史积分数据的命令
----------------------------------------------
(正在游戏场景运行中)
----------------------------------------------
客户端接受到历史积分数据,并更新显示到UnityUI界面上
----------------------------------------------
P0-玩家战机生命为0时,向服务器发送本次游戏积分数据
----------------------------------------------
服务器收到玩家本次游戏积分数据,进行数据库更新操作(根据用户名)
----------------------------------------------
客户端显示一个按钮,玩家可点击再玩一次,再次游戏(跳转P0,当玩家生命为0时)
客户端主要的代码类为WeaveSocketGameClient
(WeaveSocket框架对应为P2PClient,这里是模仿改写的便于Unity游戏客户端使用,代码内部使用的LoomUnity多线程插件).................................................
using Frankfort.Threading;
using MyTcpCommandLibrary;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using UnityEngine;
using WeaveBase;
namespace MyTcpClient
{
public class WeaveSocketGameClient
{
public Thread threadA;
public Thread threadB;
private ThreadPoolScheduler myThreadScheduler;
WeaveBaseManager xmhelper = new WeaveBaseManager();
/// <summary>
/// 是否连接成功
/// </summary>
public bool isok = false;
/// <summary>
/// 在接收数据
/// </summary>
public bool isReceives = false;
/// <summary>
/// 是否在线了
/// </summary>
public bool IsOnline = false;
DateTime timeout;
/// <summary>
/// 数据超时时间
/// </summary>
int mytimeout = 90;
/// <summary>
/// 队列中没有排队的方法需要执行
/// </summary>
List<TempPakeage> mytemppakeList = new List<TempPakeage>();
public List<byte[]> ListData = new List<byte[]>();
public string tokan;
public String ip;
public int port;
public event ReceiveMessage ReceiveMessageEvent;
public event ConnectOk ConnectOkEvent;
public event ReceiveBit ReceiveBitEvent;
public event TimeOut TimeOutEvent;
public event ErrorMessage ErrorMessageEvent;
public event JumpServer JumpServerEvent;
public TcpClient tcpClient;
// System.Threading.Thread receives_thread1;
// System.Threading.Thread checkToken_UpdateList_thread2;
SocketDataType s_datatype = SocketDataType.Json;
public WeaveSocketGameClient(SocketDataType _type)
{
s_datatype = _type;
}
#region 客户端注册类,,服务端可以按方法名调用
public void AddListenClass(object obj)
{
GetAttributeInfo(obj.GetType(), obj);
//xmhelper.AddListen()
//objlist.Add(obj);
}
public void DeleteListenClass(object obj)
{
deleteAttributeInfo(obj.GetType(), obj);
//xmhelper.AddListen()
//objlist.Add(obj);
}
public void deleteAttributeInfo(Type t, object obj)
{
foreach (MethodInfo mi in t.GetMethods())
{
InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute));
if (myattribute == null)
{
}
else
{
xmhelper.DeleteListen(mi.Name);
}
}
}
public void GetAttributeInfo(Type t, object obj)
{
foreach (MethodInfo mi in t.GetMethods())
{
InstallFunAttribute myattribute = (InstallFunAttribute)Attribute.GetCustomAttribute(mi, typeof(InstallFunAttribute));
if (myattribute == null)
{ }
else
{
Delegate del = Delegate.CreateDelegate(typeof(WeaveRequestDataDelegate), obj, mi, true);
xmhelper.AddListen(mi.Name, del as WeaveRequestDataDelegate, myattribute.Type);
}
}
}
#endregion
/// <summary>
/// 连接服务器
/// </summary>
/// <param name="_ip">IP地址</param>
/// <param name="_port">端口号</param>
/// <param name="_timeout">过期时间</param>
/// <param name="_takon">是否takon</param>
/// <returns></returns>
public bool StartConnect(string _ip, int _port, int _timeout, bool _takon)
{
mytimeout = _timeout;
ip = _ip;
port = _port;
return StartConnectToServer(ip, port, _takon);
}
public bool RestartConnectToServer(bool takon)
{
return StartConnectToServer(ip, port, takon);
}
private bool StartConnectToServer(string _ip, int _port, bool _takon)
{
try
{
if (s_datatype == SocketDataType.Json && ReceiveMessageEvent == null)
Debug.Log("没有注册receiveServerEvent事件");
if (s_datatype == SocketDataType.Json && ReceiveBitEvent == null)
Debug.Log("没有注册receiveServerEventbit事件");
ip = _ip;
port = _port;
//tcpClient = new TcpClient(ip, port);
tcpClient = new TcpClient();
// tcpc.ExclusiveAddressUse = false;
try
{
tcpClient.Connect(ip, port);
}
catch
{
return false;
}
IsOnline = true;
isok = true;
timeout = DateTime.Now;
if (!isReceives)
{
isReceives = true;
// ParameterThreadStart的定义为void ParameterizedThreadStart(object state),
// 使用这个这个委托定义的线程的启动函数可以接受一个输入参数,
//receives_thread1 = new System.Threading.Thread(new ParameterizedThreadStart(ReceivesThread));
//receives_thread1.IsBackground = true;
// receives_thread1.Start();
// ThreadStart这个委托定义为void ThreadStart(),也就是说,所执行的方法不能有参数
// checkToken_UpdateList_thread2 = new System.Threading.Thread(new ThreadStart(CheckToken_UpdateListDataThread));
//checkToken_UpdateList_thread2.IsBackground = true;
// checkToken_UpdateList_thread2.Start();
/*开始执行线程开始*/
myThreadScheduler = Loom.CreateThreadPoolScheduler();
//--------------- Ending Single threaded routine 单线程程序结束--------------------
threadA = Loom.StartSingleThread(ReceivesThread,null, System.Threading.ThreadPriority.Normal, true);
//--------------- Ending Single threaded routine 单线程程序结束--------------------
//--------------- Continues Single threaded routine 在单线程的程序--------------------
threadB = Loom.StartSingleThread(CheckToken_UpdateListDataThread, System.Threading.ThreadPriority.Normal, true);
//--------------- Continues Single threaded routine 在单线程的程序--------------------
/*开始执行线程结束*/
}
int ss = 0;
if (!_takon)
return true;
while (tokan == null)
{
// System.Threading.Thread.Sleep(1000);
// Loom.WaitForNextFrame(10);
Loom.WaitForSeconds(1);
ss++;
if (ss > 10)
return false;
}
if(ConnectOkEvent != null)
ConnectOkEvent();
return true;
}
catch (Exception e)
{
IsOnline = false;
if (ErrorMessageEvent != null)
ErrorMessageEvent( 1 , e.Message);
return false;
}
}
#region 几个方法的方法
public bool SendParameter<T>(byte command, String Request, T Parameter, int Querycount)
{
WeaveBase.WeaveSession b = new WeaveBase.WeaveSession();
b.Request = Request;
b.Token = this.tokan;
b.SetParameter<T>(Parameter);
b.Querycount = Querycount;
return SendStringCheck(command, b.Getjson());
}
public bool SendRoot<T>(byte command, String Request, T Root, int Querycount)
{
WeaveBase.WeaveSession b = new WeaveBase.WeaveSession();
b.Request = Request;
b.Token = this.tokan;
b.SetRoot<T>(Root);
b.Querycount = Querycount;
return SendStringCheck(command, b.Getjson());
}
public void Send(byte[] b)
{
tcpClient.Client.Send(b);
}
public bool SendStringCheck(byte command, string text)
{
try
{
//byte[] sendb = System.Text.Encoding.UTF8.GetBytes(text);
//byte[] part3_length = System.Text.Encoding.UTF8.GetBytes(sendb.Length.ToString());
//byte[] b = new byte[2 + part3_length.Length + sendb.Length];
//b[0] = command;
//b[1] = (byte)part3_length.Length;
//part3_length.CopyTo(b, 2);
//扩充 第四部分数据(待发送的数据)的长度,扩充到b数组第三位开始的后面
//sendb.CopyTo(b, 2 + part3_length.Length);
//扩充 第四部分数据实际的数据,扩充到b数组第三部分结尾后面...
byte[] b = MyGameClientHelper.CodingProtocol( command, text);
int count = (b.Length <= 40960 ? b.Length / 40960 : (b.Length / 40960) + 1);
if (count == 0)
{
//判定数据长度,,实际指的是大小是不是小于40kb,,,
tcpClient.Client.Send(b);
}
else
{
for (int i = 0; i < count; i++)
{
int zz = b.Length - (i * 40960) > 40960 ? 40960 : b.Length - (i * 40960);
byte[] temp = new byte[zz];
Array.Copy(b, i * 40960, temp, 0, zz);
tcpClient.Client.Send(temp);
//分割发送......
// System.Threading.Thread.Sleep(1);
// Loom.WaitForNextFrame(10);
Loom.WaitForSeconds(0.001f);
}
}
}
catch (Exception ee)
{
IsOnline = false;
CloseConnect();
if (TimeOutEvent != null)
TimeOutEvent();
SendStringCheck(command, text);
if (ErrorMessageEvent != null)
ErrorMessageEvent(9, "send:" + ee.Message);
return false;
}
// tcpc.Close();
return true;
}
public bool SendByteCheck(byte command, byte[] text)
{
try
{
//byte[] sendb = text;
//byte[] lens = MyGameClientHelper.ConvertToByteList(sendb.Length);
//byte[] b = new byte[2 + lens.Length + sendb.Length];
//b[0] = command;
//b[1] = (byte)lens.Length;
//lens.CopyTo(b, 2);
//sendb.CopyTo(b, 2 + lens.Length);
byte[] b = MyGameClientHelper.CodingProtocol(command, text);
int count = (b.Length <= 40960 ? b.Length / 40960 : (b.Length / 40960) + 1);
if (count == 0)
{
tcpClient.Client.Send(b);
}
else
{
for (int i = 0; i < count; i++)
{
int zz = b.Length - (i * 40960) > 40960 ? 40960 : b.Length - (i * 40960);
byte[] temp = new byte[zz];
Array.Copy(b, i * 40960, temp, 0, zz);
tcpClient.Client.Send(temp);
//System.Threading.Thread.Sleep(1);
// Loom.WaitForNextFrame(10);
Loom.WaitForSeconds(0.001f);
}
}
}
catch (Exception ee)
{
IsOnline = false;
CloseConnect();
if (TimeOutEvent != null)
TimeOutEvent();
SendByteCheck(command, text);
if (ErrorMessageEvent != null)
ErrorMessageEvent(9, "send:" + ee.Message);
return false;
}
// tcpc.Close();
return true;
}
#endregion
/// <summary>
/// 通过主线程执行方法避免跨线程UI问题
/// </summary>
public void OnTick()
{
if (mytemppakeList.Count > 0)
{
try
{
TempPakeage str = mytemppakeList[0];
//xmhelper.Init(str.date, null);
//receiveServerEvent(str.command, str.date);
}
catch
{
}
try
{
mytemppakeList.RemoveAt(0);
}
catch { }
}
Debug.Log("队列中没有排队的方法需要执行。");
}
public void CloseConnect()
{
try
{
isok = false;
IsOnline = false;
//发送我要断开连接的消息
this.SendRoot<int>((byte)CommandEnum.ClientSendDisConnected, "OneClientDisConnected", 0, 0);
// receives_thread1.Abort();
//checkToken_UpdateList_thread2.Abort();
tcpClient.Close();
AbortThread();
}
catch
{
Debug.Log("CloseConnect失败,发生异常");
}
}
void AbortThread()
{
if (myThreadScheduler.isBusy) //线程在此期间没有完成工作Threaded work didn't finish in the meantime: time to abort.时间终止
{
Debug.Log("Terminate all worker Threads.");
myThreadScheduler.AbortASyncThreads();
Debug.Log("Terminate thread A & B.");
if (threadA != null && threadA.IsAlive)
threadA.Interrupt();
if (threadB != null && threadB.IsAlive)
threadB.Interrupt();
}
else
{
Debug.Log("Terminate thread A & B.");
if (threadA != null && threadA.IsAlive)
threadA.Interrupt();
if (threadB != null && threadB.IsAlive)
threadB.Interrupt();
}
}
/// <summary>
/// 接收到服务器发来的数据的处理方法
/// </summary>
/// <param name="obj"></param>
void ReceiveData(object obj)
{
TempPakeage str = obj as TempPakeage;
mytemppakeList.Add(str);
if (ReceiveMessageEvent != null)
ReceiveMessageEvent(str.command, str.date);
}
/// <summary>
/// 线程启动的方法,初始化连接后要接收服务器发来的token,并更新
/// </summary>
void CheckToken_UpdateListDataThread()
{
while (isok)
{
// System.Threading.Thread.Sleep(10);
// Loom.WaitForNextFrame(10);
Loom.WaitForSeconds(0.01f);
try
{
int count = ListData.Count;
if (count > 0)
{
int bytesRead = ListData[0] != null ? ListData[0].Length : 0;
if (bytesRead == 0)
continue;
//如果到这里的continue内部,那么下面的代码不执行,重新到 --》 System.Threading.Thread.Sleep(10);开始
byte[] tempbtye = new byte[bytesRead];
//解析消息体ListData,,
Array.Copy(ListData[0], tempbtye, tempbtye.Length);
// 检查tempbtye(理论上里面应该没有0x99,有方法已经处理掉了,但是可能会有)检测还有没有0x99开头的心跳包
_0x99:
if (tempbtye[0] == 0x99)
{
if (bytesRead > 1)
{
byte[] b = new byte[bytesRead - 1];
byte[] t = tempbtye;
//把心跳包0x99去掉
Array.Copy(t, 1, b, 0, b.Length);
ListData[0] = b;
tempbtye = b;
goto _0x99;
}
else
{ //说明只有1个字节,心跳包包头,无任何意思,那么直接删除
ListData.RemoveAt(0);
continue;
}
}
//ListData[0]第一个元素的长度 大于2
if (bytesRead > 2)
{
//第二段是固定一个字节,最高255,代表了第三段的长度
//这样第三段最高可以255*255位,这样表示数据内容的长度基本可以无限大了
// int a = tempbtye[1];
int part3_Length = tempbtye[1];
//tempbtye既是ListData[0]数据,
//第一位为command,指令
//第二位的数据是第三段的长度
//第三段的数据是第四段的长度
//第四段是内容数据
if (bytesRead > 2 + part3_Length)
{ //如果收到数据这段数据,大于
// int len = 0;
int part4_Length = 0;
if (s_datatype == SocketDataType.Bytes)
{
byte[] bb = new byte[part3_Length];
byte[] part4_LengthBitArray = new byte[part3_Length];
//将tempbtye从第三位开始,复制数据到part4_LengthBitArray
Array.Copy(tempbtye, 2, part4_LengthBitArray, 0, part3_Length);
//len = ConvertToInt(bb);
//获得实际数据的长度,也就是第四部分数据的长度
part4_Length = MyGameClientHelper. ConvertToInt(part4_LengthBitArray);
}
else
{ //如果DataType不是DataType.bytes类型,,, 是Json类型
//从某个Data中第三位开始截取数据,,获取第四段数据长度的字符串string
String temp = System.Text.Encoding.UTF8.GetString(tempbtye, 2, part3_Length);
String part4_Lengthstr = System.Text.Encoding.UTF8.GetString(tempbtye, 2, part3_Length);
part4_Length = 0;
//len = 0;
//int part4_Lengthstrlength = 0;
try
{
// len = int.Parse(temp);
part4_Length = int.Parse(part4_Lengthstr);
if (part4_Length == 0) //len
{ //如果第四段数据的长度为0 ,,,说明发的空消息,,没有第四段数据
//如果第二位没有数据,,说明发的是空消息
ListData.RemoveAt(0);
continue;
}
}
catch
{
}
}
try
{
//如果计算出来的(2位数据位+第三段长度+第四度长度) 比当前ListData[0]长度还大...
if ((part4_Length + 2 + part3_Length) > tempbtye.Length)
{
if (ListData.Count > 1)
{
//将第一个数据包删除
ListData.RemoveAt(0);
//重新读取第一个数据包(第二个数据包变为第一个)内容
byte[] temps = new byte[ListData[0].Length];
//将 数据表内容 拷贝到 temps中
Array.Copy(ListData[0], temps, temps.Length);
//新byte数组长度扩充,原数据长度 + (第二个)元素长度
byte[] temps2 = new byte[tempbtye.Length + temps.Length];
Array.Copy(tempbtye, 0, temps2, 0, tempbtye.Length);
//将第一个元素ListData[0]完全从第一个地址开始 ,完全拷贝到 temps2数组中
Array.Copy(temps, 0, temps2, tempbtye.Length, temps.Length);
//将第二个元素拼接到temps2中,从刚复制数据的最后一位 +1 开始
ListData[0] = temps2;
//最后将更新数据包里面的 第一个元素为新元素
}
else
{
// System.Threading.Thread.Sleep(20);
// Loom.WaitForNextFrame(10);
Loom.WaitForSeconds(0.02f);
}
continue;
}
else if (tempbtye.Length > (part4_Length + 2 + part3_Length))
{
//如果 数据包长度 比 计算出来的(2位数据位+第三段长度+第四度长度) 还大
//考虑大出的部分
int currentAddcount = (part4_Length + 2 + part3_Length);
int offset_length = tempbtye.Length - currentAddcount;
byte[] temps = new byte[offset_length];
//Array.Copy(tempbtye, (part4_Length + 2 + part3_Length), temps, 0, temps.Length);
Array.Copy(tempbtye, currentAddcount, temps, 0, temps.Length);
//把当前ListData[0]中 后面的数据,复制到 temps数组中...
ListData[0] = temps;
}
else if (tempbtye.Length == (part4_Length + 2 + part3_Length))
{ //长度刚好匹配
ListData.RemoveAt(0);
}
}
catch (Exception e)
{
if (ErrorMessageEvent != null)
ErrorMessageEvent(3, e.StackTrace + "unup001:" + e.Message + "2 + a" + 2 + part3_Length + "---len" + part4_Length + "--tempbtye" + tempbtye.Length);
}
try
{
if (s_datatype == SocketDataType.Json)
{
//读取出第四部分数据内容,,
string temp = System.Text.Encoding.UTF8.GetString(tempbtye, 2 + part3_Length, part4_Length);
TempPakeage str = new TempPakeage();
str.command = tempbtye[0];
//命令等于第一位
str.date = temp;
//服务器发来执行是0xff,说明发送的是token指令
if (tempbtye[0] == 0xff)
{
if (temp.IndexOf("token") >= 0)
tokan = temp.Split('|')[1];
//用单个字符来分隔字符串,并获取第二个元素,,
//这里因为服务端发来的token后面跟了一个|字符
else if (temp.IndexOf("jump") >= 0)
{
//0xff就是指服务器满了
tokan = "连接数量满";
if(JumpServerEvent!=null)
JumpServerEvent(temp.Split('|')[1]);
}
else
{ // 当上面条件都不为真时执行 ,如果虽然指令是0xff,但是不包含token或jump
ReceiveData(str);
}
}
else if (ReceiveMessageEvent != null)
{
//如果tempbtye[0] == 0xff 表示token,不等的情况
ReceiveData(str);
}
}
//if (DT == DataType.bytes)
//{
// byte[] bs = new byte[len - 2 + a];
// Array.Copy(tempbtye, bs, bs.Length);
// temppake str = new temppake();
// str.command = tempbtye[0];
// str.datebit = bs;
// rec(str);
//}
continue;
}
catch (Exception e)
{
if (ErrorMessageEvent != null)
ErrorMessageEvent(3, e.StackTrace + "unup122:" + e.Message);
}
}
}
else
{ // //ListData[0]第一个元素的Length 不大于2 ,,
if (tempbtye[0] == 0)
ListData.RemoveAt(0);
}
}
}
catch (Exception e)
{
if (ErrorMessageEvent != null)
ErrorMessageEvent(3, "unup:" + e.Message + "---" + e.StackTrace);
try
{
ListData.RemoveAt(0);
}
catch { }
}
}
}
/// <summary>
/// 线程启动的方法
/// </summary>
/// <param name="obj"></param>
void ReceivesThread(object obj)
{
while (isok)
{
//System.Threading.Thread.Sleep(50);
// Loom.WaitForNextFrame(10);
Loom.WaitForSeconds(0.05f);
try
{
//可以用TcpClient的Available属性判断接收缓冲区是否有数据,来决定是否调用Read方法
int bytesRead = tcpClient.Client.Available;
if (bytesRead > 0)
{
//缓冲区
byte[] tempbtye = new byte[bytesRead];
try
{
timeout = DateTime.Now;
//从绑定接收数据 Socket 到接收缓冲区中
tcpClient.Client.Receive(tempbtye);
_0x99:
if (tempbtye[0] == 0x99)
{ //如果缓冲区第一个字符是 0x99心跳包指令
timeout = DateTime.Now;
//记录现在的时间
if (tempbtye.Length > 1)
{
//去掉第一个字节,长度总体减去1个,
byte[] b = new byte[bytesRead - 1];
try
{
//复制 Array 中的一系列元素(从指定的源索引开始),
//并将它们粘贴到另一 Array 中(从指定的目标索引开始)
//原始 Array 为tempbtye,原始Array的初始位置
//另外一个 目标 Array , 开始位置为0,长度为b.Length
Array.Copy(tempbtye, 1, b, 0, b.Length);
//那么b中的到的就是去掉心跳包指令0x99以后的后面的数据
}
catch { }
tempbtye = b;
//反复执行去掉,心跳包,,,
goto _0x99;
}
else
continue;
//后面的不执行了,回调到 上面的while循环开始 重新执行...
}
}
catch (Exception ee)
{
if(ErrorMessageEvent!=null)
ErrorMessageEvent(22, ee.Message);
}
//lock (this)
//{
//将接收到的 非心跳包数据加入到 ListData中
ListData.Add(tempbtye);
// }
}
//线程每隔指定的过期时间秒,判定,如果没有数据发送过来,,,tcpc.Client.Available=0 情况下
else
{
try
{
TimeSpan ts = DateTime.Now - timeout;
if (ts.TotalSeconds > mytimeout)
{ //判断时间过期
IsOnline = false;
CloseConnect();
//isreceives = false;
if (TimeOutEvent != null)
TimeOutEvent();
if (ErrorMessageEvent != null)
ErrorMessageEvent(2, "连接超时,未收到服务器指令");
continue;
}
}
catch (Exception ee)
{
if (ErrorMessageEvent != null)
ErrorMessageEvent(21, ee.Message);
}
}
}
catch (Exception e)
{
if (ErrorMessageEvent != null)
ErrorMessageEvent(2, e.Message);
}
}
}
}
}
MainClient单例类
using UnityEngine;
using System.Collections;
using GDGeek;
using MyTcpClient;
using System;
using UnityEngine.SceneManagement;
using WeaveBase;
using MyTcpCommandLibrary;
using UnityEngine.Events;
using MyTcpCommandLibrary.Model;
public class MainClient : Singleton<MainClient>
{
public WeaveSocketGameClient weaveSocketGameClient;
public ServerBackLoginEvent serverBackLoginEvent =new ServerBackLoginEvent();
public SetLoginTempModelEvent setLoginTempModelEvent = new SetLoginTempModelEvent();
public SetGameScoreTempModelEvent setGameScoreTempModelEvent = new SetGameScoreTempModelEvent();
public FirstCheckServerEvent firstCheckServerEvent = new FirstCheckServerEvent();
public GameScoreTempModel GameScore;
public LoginTempModel loginUserModel;
// Use this for initialization
void Start()
{
DontDestroyOnLoad(this);
setLoginTempModelEvent.AddListener(SetLoginModel);
}
public string receiveMessage;
public void InvokeSetLoginTempModelEvent(LoginTempModel _model)
{
setLoginTempModelEvent.Invoke(_model);
}
GameScoreTempModel tempGameScore;
public void CallSetGameScoreTempModelEvent(GameScoreTempModel gsModel)
{
// StartCoroutine(CallSetGameScoreEvent(gsModel));
tempGameScore = gsModel;
}
IEnumerator CallSetGameScoreEvent(GameScoreTempModel gsModel)
{
yield return new WaitForSeconds(0.5f);
setGameScoreTempModelEvent.Invoke(gsModel);
}
// Update is called once per frame
void Update()
{
//if (receiveMessage.Length != 0)
//{
// receiveMessage = string.Empty;
//}
if (canLoadSceneFlag)
{
LoadGameScene();
canLoadSceneFlag = false;
}
if (weaveSocketGameClient != null)
weaveSocketGameClient.OnTick();
if(tempGameScore != null)
{
StartCoroutine(CallSetGameScoreEvent(tempGameScore));
tempGameScore = null;
}
}
public void ConnectToServer(string serverIp,int port)
{
try
{
weaveSocketGameClient = new WeaveSocketGameClient(SocketDataType.Json);
weaveSocketGameClient.ConnectOkEvent += OnConnectOkEvent;
weaveSocketGameClient.ReceiveMessageEvent += OnReceiveMessageEvent;
weaveSocketGameClient.ErrorMessageEvent += OnErrorMessageEvent;
weaveSocketGameClient.ReceiveBitEvent += OnReceiveBitEvent;
weaveSocketGameClient.TimeOutEvent += OnTimeOutEvent;
//pcp2.AddListenClass(new MyClientFunction());
Debug.Log("初始化OK");
//bool bb = pcp2.start("61.184.86.126", 10155, false);
// bool bb = weaveSocketGameClient.StartConnect("61.184.86.126", 10155, 30, false);
bool bb = weaveSocketGameClient.StartConnect(serverIp, port, 30, false);
Debug.Log("链接OK");
firstCheckServerEvent.Invoke(bb);
}
catch
{
firstCheckServerEvent.Invoke(false);
}
}
void CallServerFunc()
{
try
{
//weaveSocketGameClient.SendRoot<int>(0x02, "login", 11111, 0);
//在加个发送
weaveSocketGameClient.tokan = "UnityTokan";
weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);
//调用服务端方法getnum,是服务端的方法。
//这样就可以了,我们试试
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
}
private void OnTimeOutEvent()
{
Debug.Log("连接超时");
//throw new NotImplementedException();
}
private void OnReceiveBitEvent(byte command, byte[] data)
{
Debug.Log("收到了Bit数据");
// throw new NotImplementedException();
}
private void OnErrorMessageEvent(int type, string error)
{
Debug.Log("发生了错误");
//throw new NotImplementedException();
}
private void OnReceiveMessageEvent(byte command, string text)
{
// throw new NotImplementedException();
Debug.Log("收到了新数据");
//throw new NotImplementedException();
receiveMessage = "指令:" + command + ".内容:" + text;
Debug.Log("原始数据是:" + receiveMessage);
try
{
WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text);
Debug.Log("接受到的WeaveSession数据是:" + ws.Request + " " + ws.Root);
}
catch
{
Debug.Log("Json转换对象出错了");
}
// receiveMessage = "指令:" + command + ".内容:" + text;
Debug.Log("收到的信息是:" + receiveMessage);
ICheckServerMessageFactory factory = CheckCommand.CheckCommandType(command);
ICheckServerMessage checkSmsg = factory.CheckServerMessage();
checkSmsg.CheckServerMessage(text);
}
private void OnConnectOkEvent()
{
Debug.Log("已经连接成功");
}
private void StopConnect()
{
if (weaveSocketGameClient != null)
{
weaveSocketGameClient.CloseConnect();
weaveSocketGameClient.ConnectOkEvent -= OnConnectOkEvent;
weaveSocketGameClient.ReceiveMessageEvent -= OnReceiveMessageEvent;
weaveSocketGameClient.ErrorMessageEvent -= OnErrorMessageEvent;
weaveSocketGameClient.ReceiveBitEvent -= OnReceiveBitEvent;
weaveSocketGameClient.TimeOutEvent -= OnTimeOutEvent;
// weaveSocketGameClient = null;
}
}
public void SendLogin(LoginTempModel user )
{
try
{
// weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0);
StartCoroutine( WaitSendLogin(user) );
Debug.Log("SendLoginFunc");
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
}
IEnumerator WaitSendLogin(LoginTempModel user)
{
yield return new WaitForSeconds(0.2f);
weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendLoginModel, "CheckLogin", user, 0);
}
public void SendCheckUserScore()
{
try
{
LoginTempModel user = loginUserModel;
// weaveSocketGameClient.Tokan = "UnityTokan";
// weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);
weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "GetUserScore", user, 0);
Debug.Log("SendLoginFunc");
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
}
public void SendNewScoreUpdate(int _score,int _missed)
{
try
{
GameScoreTempModel gsModel = new GameScoreTempModel()
{
userName = loginUserModel.userName,
missenemy = _missed,
score = _score
};
//LoginTempModel user = loginUserModel;
// weaveSocketGameClient.Tokan = "UnityTokan";
// weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);
weaveSocketGameClient.SendRoot<GameScoreTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "UpdateScore", gsModel, 0);
Debug.Log("UpdateScore");
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
}
public int sceneIndex;
public bool canLoadSceneFlag;
void LoadGameScene()
{
SceneManager.LoadScene(1);
}
public void SetLoadSceneFlag()
{
canLoadSceneFlag = true;
}
void OnDestroy()
{
//SetLoginModelEvent.RemoveListener(SetLoginModel);
}
private void SetLoginModel(LoginTempModel _model)
{
loginUserModel = _model;
}
private void OnApplicationQuit()
{
StopConnect();
}
}
public class SetLoginTempModelEvent : UnityEvent<LoginTempModel> { }
public class SetGameScoreTempModelEvent : UnityEvent<GameScoreTempModel> { }
public class ServerBackLoginEvent : UnityEvent<bool>{}
public class FirstCheckServerEvent : UnityEvent<bool> { }
登陆界面类
using MyTcpCommandLibrary.Model;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class LoginHandler : MonoBehaviour {
public InputField input_Username;
public InputField input_Password;
public InputField input_ServerIP;
public InputField input_ServerPort;
public Text server_msg_text;
public Button login_button;
// public LoginModel userModel;
// Use this for initialization
void Start() {
MainClient.Instance.serverBackLoginEvent.AddListener(GetServerBackLoginEvent);
MainClient.Instance.firstCheckServerEvent.AddListener(firstCheckServerConfigEvent);
}
private void firstCheckServerConfigEvent(bool connectToServerResult)
{
// throw new NotImplementedException();
connectedServerOK = connectToServerResult;
}
public void SetServerIP_Connected()
{
string ip = input_ServerIP.text;
int port = int.Parse(input_ServerPort.text);
if(connectedServerOK ==false)
MainClient.Instance.ConnectToServer(ip, port);
}
private void GetServerBackLoginEvent(bool arg0)
{
//throw new NotImplementedException();
server_msg = "登陆失败,账号密码错误...";
}
public bool connectedServerOK = false;
public void Login()
{
LoginTempModel model = new LoginTempModel()
{
userName = input_Username.text,
password = input_Password.text,
//userName = "ssss",
//password = "yyyyyy",
logintime = System.DateTime.Now.ToString("yyyyMMddHHmmssfff")
};
// userModel = model;
MainClient.Instance.InvokeSetLoginTempModelEvent(model);
MainClient.Instance.SendLogin(model);
}
private string server_msg = "";
public void SetServerMsgShow(string serverMsg)
{
server_msg_text.text = serverMsg;
}
void OnDestroy()
{
MainClient.Instance.serverBackLoginEvent.RemoveListener(GetServerBackLoginEvent);
MainClient.Instance.firstCheckServerEvent.RemoveListener(firstCheckServerConfigEvent);
}
// Update is called once per frame
void Update () {
if( string.IsNullOrEmpty( server_msg) ==false || server_msg.Length >2)
{
SetServerMsgShow(server_msg);
login_button.gameObject.SetActive(true);
server_msg = "";
}
}
}
游戏场景界面UI控制显示类
using UnityEngine;
using System.Collections;
using UnityEngine.Events;
using UnityEngine.UI;
using System;
using MyTcpCommandLibrary.Model;
public class GameScoreHandler : MonoBehaviour
{
public static UpdateScoreEvent updateScoreEvent = new UpdateScoreEvent();
public static UpdateLivesEvent updateLivesEvent = new UpdateLivesEvent();
public static UpdateMissedEvent updateMissedEvent = new UpdateMissedEvent();
public static UnityEvent SendUpdateScoreEvent = new UnityEvent();
// public static UnityEvent<GameScoreTempModel> SetGameScoreUI;
public Text userNameText;
public Text now_scoreText;
public Text now_livesText;
public Text now_missedText;
public Text serverText;
public Text last_scoreText;
public Text last_missedText;
// Use this for initialization
void Start()
{
updateScoreEvent.AddListener( OnUpdateScore);
updateLivesEvent.AddListener(OnUpdateLives);
updateMissedEvent.AddListener(OnUpdateMissed);
SendUpdateScoreEvent.AddListener(OnSendUpdateScore);
MainClient.Instance.setGameScoreTempModelEvent.AddListener(SetLastData);
}
private void OnSendUpdateScore()
{
//throw new NotImplementedException();
serverText.text = "积分已发往服务器...";
}
private void OnUpdateScore(int _score)
{
now_scoreText.text = "积分:" + _score.ToString();
}
void OnDestory()
{
updateScoreEvent.RemoveListener(OnUpdateScore);
updateLivesEvent.RemoveListener(OnUpdateLives);
updateMissedEvent.RemoveListener(OnUpdateMissed);
SendUpdateScoreEvent.RemoveListener(OnSendUpdateScore);
MainClient.Instance.setGameScoreTempModelEvent.RemoveListener(SetLastData);
}
private void OnUpdateLives(int _lives)
{
now_livesText.text = "生命:" + _lives.ToString();
}
private void OnUpdateMissed(int _missed)
{
now_missedText.text = "放走敌人:" + _missed.ToString();
}
private void OnDestroy()
{
}
public void SetUserNameData(string _uname)
{
userNameText.text = _uname;
}
public void SetLastData(GameScoreTempModel gsModel)
{
//userNameText.text = "生命:" + gsModel.userName;
//last_scoreText.text = "积分:" + gsModel.score.ToString();
//last_missedText.text = "放走敌人:" + gsModel.missenemy.ToString();
tempScore = gsModel;
}
public void SetLastDataText()
{
userNameText.text = "生命:" + tempScore.userName;
last_scoreText.text = "积分:" + tempScore.score.ToString();
last_missedText.text = "放走敌人:" + tempScore.missenemy.ToString();
}
public void SetNowDate(int _lives, int _lastScore, int _lastMissed)
{
now_livesText.text ="生命:"+ _lives.ToString();
now_scoreText.text = "积分:" + _lastScore.ToString();
now_missedText.text = "放走敌人:" + _lastMissed.ToString();
}
GameScoreTempModel tempScore;
// Update is called once per frame
void Update()
{
if(tempScore != null)
{
SetLastDataText();
tempScore = null;
}
}
public void ReloadGameScene()
{
//跳转场景
MainClient.Instance.SetLoadSceneFlag();
//发送读取上次分数数据的逻辑
MainClient.Instance.SendCheckUserScore();
}
}
public class UpdateScoreEvent: UnityEvent<int> { }
public class UpdateLivesEvent : UnityEvent<int> { }
public class UpdateMissedEvent : UnityEvent<int> { }
客户端使用的主要代码为
WeaveSocketGameClient weaveSocketGameClient = new WeaveSocketGameClient(SocketDataType.Json);
weaveSocketGameClient.ConnectOkEvent += OnConnectOkEvent;
weaveSocketGameClient.ReceiveMessageEvent += OnReceiveMessageEvent;
weaveSocketGameClient.ErrorMessageEvent += OnErrorMessageEvent;
weaveSocketGameClient.ReceiveBitEvent += OnReceiveBitEvent;
weaveSocketGameClient.TimeOutEvent += OnTimeOutEvent;
Debug.Log("初始化OK");
bool bb = weaveSocketGameClient.StartConnect(serverIp, port, 30, false);
Debug.Log("链接OK");
//触发第一次 检查并连接服务器状态事件,用于通知其它Unity脚本,作出相应反应
firstCheckServerEvent.Invoke(bb);
没什么可说的,代码已经很明确了,常用的几个事件都有,,
具体说一下MainClient类里面的 接收数据处理用的抽象工厂
在接收事件处理方法里面写有如下代码
Debug.Log("收到了新数据");
receiveMessage = "指令:" + command + ".内容:" + text;
Debug.Log("原始数据是:" + receiveMessage);
try
{
WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text);
Debug.Log("接受到的WeaveSession数据是:" + ws.Request + " " + ws.Root);
}
catch
{
Debug.Log("Json转换对象出错了");
}
Debug.Log("收到的信息是:" + receiveMessage);
//根据收到的指令来确定要生成的工厂
ICheckServerMessageFactory factory = CheckCommand.CheckCommandType(command);
//调用对应工厂,生成具体的接口实现类
ICheckServerMessage checkSmsg = factory.CheckServerMessage();
//调用具体接口类的 处理数据的具体方法
checkSmsg.CheckServerMessage(text);
抽象工厂以及相关代码如下
帮助类,也可直接写成Switch,这里避免代码过长,所以封装了一下
using UnityEngine;
using System.Collections;
public static class CheckCommandHelper
{
public static ICheckServerMessageFactory SwitchCheckCommand(byte command)
{
ICheckServerMessageFactory factory = null;
switch (command)
{
case (0x1):
factory = new LoginMessageFactory();
break;
case (0x2):
factory = new GameScoreMessageFactory();
break;
//其他类型略;
}
return factory;
}
}
工厂接口
using System;
public interface ICheckServerMessageFactory
{
ICheckServerMessage CheckServerMessage();
}
数据处理接口
using System;
public interface ICheckServerMessage
{
void CheckServerMessage( string text);
}
具体实现类
using UnityEngine;
using System.Collections;
using System;
using WeaveBase;
public class LoginMessage : ICheckServerMessage
{
public void CheckServerMessage( string text)
{
// throw new NotImplementedException();
WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text);
Debug.Log("收到的消息是:"+text);
if(ws.Request == "ServerBackLoginResult" )
{
if( ws.GetRoot<bool>() == true)
{
//如果登陆成功,,处理的逻辑......
//先更新用户
//跳转场景
MainClient.Instance.SetLoadSceneFlag();
//发送读取上次分数数据的逻辑
MainClient.Instance.SendCheckUserScore();
}
else
{
MainClient.Instance.serverBackLoginEvent.Invoke(false);
}
}
}
}
using UnityEngine;
using System.Collections;
using System;
using WeaveBase;
using MyTcpCommandLibrary.Model;
public class GameScoreMessage : ICheckServerMessage
{
public void CheckServerMessage(string text)
{
// throw new NotImplementedException();
WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text);
Debug.Log("收到的GameScoreMessage消息是:" + text);
if (ws.Request == "ServerSendGameScore")
{
GameScoreTempModel gsModel = ws.GetRoot<GameScoreTempModel>();
if (gsModel != null )
{
MainClient.Instance.CallSetGameScoreTempModelEvent(gsModel);
}
else
{
// MainClient.Instance.serverBackLoginEvent.Invoke(false);
}
}
}
}
using UnityEngine;
using System.Collections;
using System;
public class LoginMessageFactory : ICheckServerMessageFactory
{
public ICheckServerMessage CheckServerMessage()
{
//throw new NotImplementedException();
return new LoginMessage();
}
}
using UnityEngine;
using System.Collections;
public class GameScoreMessageFactory : ICheckServerMessageFactory
{
public ICheckServerMessage CheckServerMessage()
{
//throw new NotImplementedException();
return new GameScoreMessage();
}
}
命令的枚举
using System;
namespace MyTcpCommandLibrary
{
public enum CommandEnum :byte
{
/// <summary>
///
/// </summary>
ClientSendLoginModel = 0x02,
ClientSendGameScoreModel = 0x03,
ServerSendLoginResult = 0x04,
// ServerSendGameScoreModel = 0x05,
ClientSendDisConnected = 0x06,
ServerSendUpdateGameScoreResult = 0x07,
ClientSendCheckScore = 0x08,
ServerSendGetGameScoreResult = 0x09
}
}
-------------------------------------------
让我们再次来理一理客户端逻辑
-------------------------------------------
----------------------------------------------
启动程序
----------------------------------------------
玩家输入账号密码
----------------------------------------------
点击登陆按钮,
----------------------------------------------
调用MainClient里面的ConnectToServer 方法
----------------------------------------------
连接服务器(如果成功),继续发送账号密码到服务器的命令
----------------------------------------------
再调用MainClient里面的 SendLogin 方法(有个等待0.2秒)
----------------------------------------------
服务器接收账号密码,进行查找数据库操作
----------------------------------------------
调用了MyTcpCommandLibrary项目中的LoginManageCommand类的CheckLogin方法(具体LiteDB操作数据的代码不再细说,源码一看就明白了)
[InstallFun("forever")]
public void CheckLogin(Socket soc, WeaveSession wsession)
{
// string jsonstr = _0x01.Getjson();
LoginTempModel get_client_Send_loginModel = wsession.GetRoot<LoginTempModel>();
//执行查找数据的操作......
bool loginOk = false;
AddSystemData();
loginOk = CheckUserCanLoginIn(get_client_Send_loginModel);
if (loginOk)
{
// UpdatePlayerListSetOnLine 发送有玩家成功登陆服务器事件,用于通知前端更新UserListBox
ServerLoginOKEvent(get_client_Send_loginModel.userName, soc);
}
SendRoot<bool>(soc, (byte)CommandEnum.ServerSendLoginResult, "ServerBackLoginResult", loginOk , 0, wsession.Token);
//发送人数给客户端
//参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token
}
----------------------------------------------
发送查找结果给客户端......
----------------------------------------------
如果客户端接收到服务器发过来的登陆成功消息(跳转到游戏场景),
----------------------------------------------
数据处理工厂接收到命令调用LoginMessageFactory,并返回一个具体的ICheckServerMessage接口实现类LoginMessage
----------------------------------------------
调用它的CheckServerMessage方法
-----------------------------------------------
using UnityEngine;
using System.Collections;
using System;
using WeaveBase;
public class LoginMessage : ICheckServerMessage
{
public void CheckServerMessage( string text)
{
// throw new NotImplementedException();
WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text);
Debug.Log("收到的消息是:"+text);
if(ws.Request == "ServerBackLoginResult" )
{
if( ws.GetRoot<bool>() == true)
{
//如果登陆成功,,处理的逻辑......
//先更新用户
//跳转场景
MainClient.Instance.SetLoadSceneFlag();
//发送读取上次分数数据的逻辑
MainClient.Instance.SendCheckUserScore();
}
else
{
MainClient.Instance.serverBackLoginEvent.Invoke(false);
}
}
}
}
----------------------------------------------
如果返回失败,那么提示账号密码错误
----------------------------------------------
客户端再次发送查找当前用户的历史积分数据的命令
----------------------------------------------
既是上面代码中的//发送读取上次分数数据的逻辑
MainClient.Instance.SendCheckUserScore();方法里面已经封装了用户的UserName
具体方法代码是
LoginTempModel user = loginUserModel;
weaveSocketGameClient.SendRoot<LoginTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "GetUserScore", user, 0);
----------------------------------------------
(正在游戏场景运行中)
----------------------------------------------
客户端接受到历史积分数据,并更新显示到UnityUI界面上
----------------------------------------------
同上..................调用实现接口ICheckServerMessage的具体类GameScoreMessage的CheckServerMessage方法
----------------------------------------------
using UnityEngine;
using System.Collections;
using System;
using WeaveBase;
using MyTcpCommandLibrary.Model;
public class GameScoreMessage : ICheckServerMessage
{
public void CheckServerMessage(string text)
{
// throw new NotImplementedException();
WeaveSession ws = Newtonsoft.Json.JsonConvert.DeserializeObject<WeaveSession>(text);
Debug.Log("收到的GameScoreMessage消息是:" + text);
if (ws.Request == "ServerSendGameScore")
{
GameScoreTempModel gsModel = ws.GetRoot<GameScoreTempModel>();
if (gsModel != null )
{
//触发收到服务器发送来的积分数据的事件,并更新到前端UI显示上
MainClient.Instance.CallSetGameScoreTempModelEvent(gsModel);
}
else
{
// MainClient.Instance.serverBackLoginEvent.Invoke(false);
}
}
}
}
----------------------------------------------
P0-玩家战机生命为0时,向服务器发送本次游戏积分数据
----------------------------------------------
调用MainClient里面的SendNewScoreUpdate方法
----------------------------------------------
public void SendNewScoreUpdate(int _score,int _missed)
{
try
{
GameScoreTempModel gsModel = new GameScoreTempModel()
{
userName = loginUserModel.userName,
missenemy = _missed,
score = _score
};
//LoginTempModel user = loginUserModel;
// weaveSocketGameClient.Tokan = "UnityTokan";
// weaveSocketGameClient.SendRoot<int>(0x01, "getnum", 0, 0);
weaveSocketGameClient.SendRoot<GameScoreTempModel>((byte)CommandEnum.ClientSendGameScoreModel, "UpdateScore", gsModel, 0);
Debug.Log("UpdateScore");
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
}
----------------------------------------------
服务器收到玩家本次游戏积分数据,进行数据库更新操作(根据用户名)
----------------------------------------------
调用了MyTcpCommandLibrary项目中的GameScoreCommand类的UpdateScore方法(具体LiteDB操作数据的代码不再细说,源码一看就明白了)
----------------------------------------------
[InstallFun("forever")]
public void UpdateScore(Socket soc, WeaveSession wsession)
{
GameScoreTempModel gsModel = wsession.GetRoot<GameScoreTempModel>();
//执行数据更新的操作......
bool updateSocreResult = UpdateUserScore(gsModel.userName, gsModel.score , gsModel.missenemy);
if (updateSocreResult)
{
// 向客户端发送 更新积分成功的信息
SendRoot<bool>(soc, (byte)CommandEnum.ServerSendUpdateGameScoreResult, "ServerSendUpdateGameScoreResult", updateSocreResult, 0, wsession.Token);
}
else
{
// 向客户端发送 更新积分失败的信息
SendRoot<bool>(soc, (byte)CommandEnum.ServerSendUpdateGameScoreResult, "ServerSendUpdateGameScoreResult", updateSocreResult, 0, wsession.Token);
//发送人数给客户端
//参数1,发送给客户端对象,参数2,发送给客户端对应的方法,参数3,人数的实例,参数4,此处无作用,参数5,客户端此次token
}
}
----------------------------------------------
客户端显示一个按钮,玩家可点击再玩一次,再次游戏(跳转P0,当玩家生命为0时)
----------------------------------------------
GameScoreHandler类的ReloadGameScene方法,发送本次游戏积分数据并重新加载游戏场景
---------------------------------------
其它的Unity3D游戏逻辑代码在这里不再细说