接下来 先讲讲服务端的吧
代码部分解析
这里两个类都要引用 KGSocket dll的
1.ChatNetData 建立一个 客户端 服务端共用的数据 类库 因为要互相传的所以肯定要统一
目标框架要选择这个Unity 3.5 .net Subset Base Class Libraries 1.png导出的dll Unity 才能用
里面就是一些数据结构了
网络消息自定义类 要继承KGNetData 打上Serializable 序列化标签
枚举那些因为没办法序列化所以用Int的代替然后接收到再强转回来
using KGSocket;
using System;
namespace ChatNetData
{
[Serializable]
public class ChatDatas:KGNetData
{
public byte[] HeadData;
public string PlayerName;
public SendChat Chatdata;
}
}
namespace ChatNetData
{
public enum CMD
{
None,
ReqLogin,
ReqChatInfo,
RspLogin,
RspChatInfo,
}
}
namespace ChatNetData
{
public enum ErrorInfo
{
None,
NameRepeatsErr,//名字重复登录错误指令
}
}
using System;
namespace ChatNetData
{
[Serializable]
public class SendChat
{
public string chat;
public int Islocal;
}
}
2.ChatDatasPack 用于分辨数据是哪个客户端发定的数据类型**
using ChatNetData;
namespace ChatServer
{
public class ChatDatasPack
{
public ChatSession chatSession;
public ChatDatas chatDatas;
}
}
using ChatNetData;
namespace ChatServer
{
public class ChatDatasPack
{
public ChatSession chatSession;
public ChatDatas chatDatas;
}
}
3.ChatSessio 每个客户端的通信都是他来操作**
要继承KGNetSession<ChatDatas> ChatDatas就是自己定义继承KGNetData的数据类
这里主要的就是 OnDisRecive 断开回调 ,OnReciveData接收到数据回调 OnStartRecive 连接成功回调
OnReciveData(ChatDatas data) 接收到数据会 new一个ChatDatasPack 赋值 添加到ChatServe的任务队列 排序处理
using KGSocket;
using ChatNetData;
namespace ChatServer
{
public class ChatSession : KGNetSession<ChatDatas>
{
public int SessionID = 0;
public string PlayerName;//缓存用户的名字public byte[] HeadData;//缓存用户的头像图片数据
protected override void OnDisRecive()
{
("名字:" + PlayerName + "已下线").KLog();
}
protected override void OnReciveData(ChatDatas data)
{
("收到名字:" + data.PlayerName + "的请求"+(CMD)data.Cmd).KLog();
ChatServe.Instance.AddDataPackQue(this,data);
}
protected override void OnStartRecive()
{
SessionID = ChatServe.Instance.GetSessionID();
("ID:" + SessionID + "已连接").KLog();
}
}
}
4.ChatServe 这个就是创建服务器socket的了 缓存客户端 处理接收各个客户端信息返回的业务逻辑
要继承KGSocketServe<ChatSession, ChatDatas>
这里AddDataPackQue 就是添加接收到的消息任务队列的,会用到一个线程锁,
lock 这里简单说一下 作用是被lock的对象,里面的语句块 一次只被一个线程使用 如果在使用中的 其他线程就会排队等待执行完再轮到下一个 不会出现一窝蜂调用 顺序错乱情况
添加完后 在Update() 这里进行出列调用 主线程那边就可以直接一直调用Update一直刷新有没有新的任务队列就好
然后DisposePack这里就是处理从客户端接收到的数据了 判断指令调用对应业务逻辑
using System.Linq;
using KGSocket;
using ChatNetData;
namespace ChatServer
{
public class ChatServe : KGSocketServe<ChatSession, ChatDatas>
{
private static ChatServe instance;
public static ChatServe Instance
{
get
{
if (instance == null)
{
instance = new ChatServe();
}
return instance;
}
set => instance = value;
}
public static readonly object obj = "lock";
public Queue<ChatDatasPack> DataPackQue = new Queue<ChatDatasPack>();
#region 缓存
private int SessionID = 0;
public int GetSessionID()
{
if (SessionID == int.MaxValue)
{
SessionID = 0;
}
return SessionID += 1;
}
public bool IsUserOnLine(string name)
{
return SessionList.Select(v=>v.PlayerName).ToList().Contains(name) ;
}
#endregion
public void Update()
{
if (DataPackQue.Count>0)
{
lock (obj)
{
DisposePack(DataPackQue.Dequeue());
}
}
}
public void DisposePack(ChatDatasPack pack)
{
switch ((CMD)pack.chatDatas.Cmd)
{
case CMD.ReqLogin:
//判断在线的名字是否重复
if (IsUserOnLine(pack.chatDatas.PlayerName))
{
pack.chatDatas.Err = (int)ErrorInfo.NameRepeatsErr;
}
else
{
pack.chatSession.PlayerName = pack.chatDatas.PlayerName;
pack.chatSession.HeadData = pack.chatDatas.HeadData;
pack.chatDatas.Cmd = (int)CMD.RspLogin;
}
pack.chatSession.SendData(pack.chatDatas);
break;
case CMD.ReqChatInfo:
pack.chatDatas.Cmd = (int)CMD.RspChatInfo;
pack.chatDatas.HeadData = pack.chatSession.HeadData;
pack.chatDatas.PlayerName = pack.chatSession.PlayerName;
//发回给自身聊天
pack.chatSession.SendData(pack.chatDatas);
//改成对方
pack.chatDatas.Chatdata.Islocal = 1;
//分发到各个客户端 聊天消息
SessionList.Where(v=>v!=pack.chatSession).ToList().ForEach(v=>
{
v.SendData(pack.chatDatas);
});
break;
}
}
public void AddDataPackQue(ChatSession session, ChatDatas chatData)
{
lock (obj)
{
DataPackQue.Enqueue(new ChatDatasPack { chatSession = session, chatDatas = chatData });
}
}
}
}
https://github.com/LKaiGuo/KGScriptGenerator 喜欢的给我点个星星啊
u3d萌新QQ群844087555 欢迎进来灌水=。=
网友评论