- 通用服务端框架,具有粘包半包处理、协议解析等功能,服务端使用多路复用,单进程单线程
客户端
using Assets.Scripts.Net.Proto;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
public delegate void EventListener(string err);
public delegate void MsgListener(MsgBase msg);
public static class NetManager
{
//是否启用心跳
public static bool isUsePing = true;
//心跳间隔时间
public static int pingInterval = 30;
//上一次发送Ping时间
public static float lastPingTime = 0;
//上一次接收Pong时间
public static float lastPongTime = 0;
//消息监听字典
private static Dictionary<string, MsgListener> MsgListenerDic = new Dictionary<string, MsgListener>();
//事件监听字典
private static Dictionary<NetEvent, EventListener> EventListenerDic = new Dictionary<NetEvent, EventListener>();
//是否正在断开连接
private static bool isClosing;
//是否正在连接
private static bool isConnecting;
private static Socket socket;
//读取数据缓存
private static byte[] readBuff;
//数据缓存大小
public static int BuffTotalCount = 2048;
//接收缓冲区的数据长度
private static int buffcount;
//发送消息缓存队列
private static Queue<byte[]> writeQueue;
//接收消息缓存列表
private static List<MsgBase> msgList;
//接收消息缓存列表数量
private static int msgCount;
//每一次Update处理的消息量
readonly static int MAX_MESSAGE_FIRE = 10;
//初始化
private static void InitState()
{
//上次发送Ping时间
lastPingTime = Time.time;
//上次收到Pong时间
lastPongTime = Time.time;
isClosing = false;
socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
readBuff = new byte[BuffTotalCount];
writeQueue = new Queue<byte[]>();
msgList = new List<MsgBase>();
msgCount = 0;
buffcount = 0;
if (!MsgListenerDic.ContainsKey("MsgPong"))
{
MsgListenerDic.Add("MsgPong", OnMsgPong);
}
}
/// <summary>
/// 发送Ping协议
/// </summary>
private static void PingUpdate()
{
if (!isUsePing)
{
return;
}
if (socket==null||!socket.Connected)
{
return;
}
//发送Ping
if (Time.time-lastPingTime>pingInterval)
{
MsgPing ping = new MsgPing("MsgPing");
Send(ping);
lastPingTime = Time.time;
}
if (Time.time - lastPongTime > pingInterval*4)
{
socket.Close();
socket.Dispose();
}
}
private static void OnMsgPong(MsgBase msg)
{
lastPongTime = Time.time;
}
/// <summary>
/// 连接服务器
/// </summary>
/// <param name="ip">服务器Ip</param>
/// <param name="port">端口号</param>
public static void Connect(string ip , int port)
{
if (socket!=null&&socket.Connected)
{
Debug.Log("已连接!!!");
return;
}
if (isConnecting)
{
Debug.Log("正在连接.....");
}
isConnecting = false;
InitState();
socket.BeginConnect(ip,port, ConnectCallBack,socket);
}
/// <summary>
/// 断开连接
/// </summary>
public static void Close()
{
if (socket==null||!socket.Connected)
{
Debug.Log("未能断开连接,原因:未连接服务器");
return;
}
if (isConnecting)
{
Debug.Log("未能断开连接,原因:未连接服务器");
return;
}
if (writeQueue.Count>0)
{
isClosing = true;
}
else
{
socket.Close();
FireEvent(NetEvent.Close,"");
}
}
/// <summary>
/// 发送消息
/// </summary>
public static void Send(MsgBase msg)
{
if (socket==null||!socket.Connected)
{
Debug.Log("发送失败,未连接服务器!");
return;
}
if (isConnecting)
{
Debug.Log("发送失败,正在连接服务器。。。。");
return;
}
if (isClosing)
{
Debug.Log("发送失败,正在断开连接。。。。");
return;
}
//数据编码
byte[] nameBytes = MsgBase.EncodeProtoName(msg);
byte[] bodyBytes = MsgBase.Encode(msg);
int totalLen = nameBytes.Length + bodyBytes.Length;
byte[] sendBytes = new byte[totalLen + 2];
sendBytes[0] = (byte)(totalLen % 256);
sendBytes[1] = (byte)(totalLen / 256);
Array.Copy(nameBytes, 0, sendBytes, 2, nameBytes.Length);
Array.Copy(bodyBytes,0,sendBytes, nameBytes.Length+2,bodyBytes.Length);
int count = 0;
lock (writeQueue)
{
writeQueue.Enqueue(sendBytes);
count = writeQueue.Count;
}
if (count>0)
{
socket.BeginSend(sendBytes,0,sendBytes.Length,0, SendCallBack,socket);
}
}
/// <summary>
/// 更新消息
/// </summary>
public static void MsgUpdate()
{
if (msgCount == 0)
{
return;
}
for (int i = 0; i < MAX_MESSAGE_FIRE; i++)
{
//获取第一条消息
MsgBase msg = null;
lock (msgList)
{
if (msgList.Count>0)
{
msg = msgList[0];
msgList.RemoveAt(0);
msgCount--;
}
}
if (msg!=null)
{
FireMsg(msg.protoName,msg);
}
else
{
break;
}
}
}
/// <summary>
/// 发送消息回调
/// </summary>
/// <param name="asyncResult"></param>
private static void SendCallBack(IAsyncResult asyncResult)
{
Socket socket = asyncResult.AsyncState as Socket;
if (socket==null||!socket.Connected)
{
return;
}
//EndSend
int count = socket.EndSend(asyncResult);
//取出队列第一个消息
byte[] ba;
lock (writeQueue)
{
ba = writeQueue.Peek();
}
int idx = count;
if (ba.Length == count)
{
idx = 0;
lock (writeQueue)
{
writeQueue.Dequeue();
ba = writeQueue.Count > 0 ? writeQueue.Peek() : null;
}
}
if (ba != null)
{
socket.BeginSend(ba,idx,ba.Length,0,SendCallBack,socket);
}
else if(isClosing)
{
socket.Close();
}
}
//连接回调
private static void ConnectCallBack(IAsyncResult asyncResult)
{
try
{
Socket socket = asyncResult.AsyncState as Socket;
socket.EndConnect(asyncResult);
isConnecting = false;
FireEvent(NetEvent.ConnectSucc,"");
socket.BeginReceive(readBuff,buffcount,BuffTotalCount-buffcount,0, ReciveCallBack,socket);
}catch(SocketException ex)
{
isConnecting = false;
Debug.Log("连接失败:"+ex.ToString());
FireEvent(NetEvent.ConnectFail,"");
}
}
private static void ReciveCallBack(IAsyncResult asyncResult)
{
Socket socket = asyncResult.AsyncState as Socket;
int count = socket.EndReceive(asyncResult);
buffcount += count;
OnReciveData();
//继续接收数据
socket.BeginReceive(readBuff,buffcount,BuffTotalCount- buffcount, 0,ReciveCallBack,socket);
}
/// <summary>
/// 处理缓冲区消息(解决粘包问题)
/// </summary>
private static void OnReciveData()
{
//消息不足够长
if (buffcount <= 2)
{
return;
}
Int16 bodyLen = (Int16)(readBuff[1] << 8 | readBuff[0]);
if (buffcount<bodyLen+2)
{
return;
}
//string s = Encoding.UTF8.GetString(readBuff,2,bodyLen);
int nameCount = 0;
int start = 2 + bodyLen;
int count = buffcount - start;
//解析协议名
string protoName = MsgBase.DecodeProtoName(readBuff,2,out nameCount);
if (protoName=="")
{
Debug.Log("OnReciveData MsgBase.DecodeProtoName:Fail");
return;
}
int readIdx = 2 + nameCount;
MsgBase msgBase = MsgBase.Decode(protoName,readBuff,readIdx,bodyLen-nameCount);
//添加消息
lock (msgList)
{
msgList.Add(msgBase);
}
msgCount++;
Array.Copy(readBuff,start,readBuff,0,count);
buffcount -= start;
OnReciveData();
}
//分发消息
private static void FireEvent(NetEvent netEvent,string err)
{
if (EventListenerDic.ContainsKey(netEvent)&& EventListenerDic[netEvent]!=null)
{
EventListenerDic[netEvent](err);
}
}
/// <summary>
/// 添加监听事件
/// </summary>
/// <param name="netEvent"></param>
/// <param name="listener"></param>
public static void AddListener(NetEvent netEvent,EventListener listener)
{
if (EventListenerDic.ContainsKey(netEvent))
{
EventListenerDic[netEvent] += listener;
}
else
{
EventListenerDic.Add(netEvent,listener);
}
}
/// <summary>
/// 移除监听事件
/// </summary>
/// <param name="netEvent"></param>
/// <param name="listener"></param>
public static void RemoveListener(NetEvent netEvent, EventListener listener)
{
if (EventListenerDic.ContainsKey(netEvent))
{
if (EventListenerDic[netEvent]!=null)
{
EventListenerDic[netEvent] -= listener;
}
else
{
EventListenerDic.Remove(netEvent);
}
}
}
/// <summary>
/// 添加消息监听
/// </summary>
/// <param name="msgName">消息名称</param>
/// <param name="msgListener">回调函数</param>
public static void AddMsgListener(string msgName , MsgListener msgListener)
{
if (MsgListenerDic.ContainsKey(msgName))
{
MsgListenerDic[msgName] += msgListener;
}
else
{
MsgListenerDic[msgName] = msgListener;
}
}
/// <summary>
/// 移除消息监听
/// </summary>
/// <param name="msgName">消息类型名称</param>
/// <param name="msgListener">回调函数</param>
public static void RemoveMsgListener(string msgName,MsgListener msgListener)
{
if (MsgListenerDic.ContainsKey(msgName))
{
if (MsgListenerDic[msgName]!=null)
{
MsgListenerDic[msgName] -= msgListener;
}
else
{
MsgListenerDic.Remove(msgName);
}
}
}
/// <summary>
/// 分发消息
/// </summary>
/// <param name="msgName">消息类型</param>
/// <param name="msg">消息类</param>
private static void FireMsg(string msgName,MsgBase msg)
{
if (MsgListenerDic.ContainsKey(msgName)&& MsgListenerDic[msgName]!=null)
{
MsgListenerDic[msgName](msg);
}
}
public static void Update()
{
MsgUpdate();
PingUpdate();
}
}
public enum NetEvent
{
ConnectSucc = 1,
ConnectFail = 2,
Close = 3,
}
客户端MsgBase 协议基类
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using Assets.Scripts.Models;
[System.Serializable]
public class MsgBase
{
//协议名
public string protoName="";
public MsgBase(string protoName)
{
this.protoName = protoName;
}
public static byte[] Encode(MsgBase msgBase)
{
string json = JsonUtility.ToJson(msgBase);
return Encoding.UTF8.GetBytes(json);
}
public static MsgBase Decode(string protoName,byte[] bytes,int offset,int count)
{
string json = Encoding.UTF8.GetString(bytes,offset,count);
string typeName = "Assets.Scripts.Net.Proto." + protoName;
MsgBase msg = (MsgBase)JsonUtility.FromJson(json,Type.GetType(typeName));
return msg;
}
/// <summary>
/// 编码协议名
/// </summary>
/// <param name="msg">协议</param>
/// <returns></returns>
public static byte[] EncodeProtoName(MsgBase msg)
{
byte[] nameBytes = Encoding.UTF8.GetBytes(msg.protoName);
int nameLen = nameBytes.Length;
byte[] ret = new byte[nameLen+2];
ret[0] = (byte)(nameLen % 256);
ret[1] = (byte)(nameLen / 256);
Array.Copy(nameBytes,0,ret,2,nameLen);
return ret;
}
/// <summary>
/// 解码协议名
/// </summary>
/// <param name="bytes"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
/// <returns></returns>
public static string DecodeProtoName(byte[] bytes,int offset,out int count)
{
count = 0;
if (offset+2>bytes.Length)
{
return "";
}
//读取长度
Int16 len = (Int16)(bytes[offset + 1] << 8 | bytes[offset]);
if (len<=0)
{
count = 2;
return "";
}
if (offset+2+len>bytes.Length)
{
return "";
}
count = 2 + len;
string name = Encoding.UTF8.GetString(bytes,offset+2,len);
return name;
}
}
服务端NetManager
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
namespace SeverManager
{
public class NetManager
{
//监听Socket
static Socket listenfd;
//客户端Socket和状态信息
public static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
//Select的检查列表
public static List<Socket> checkRead = new List<Socket>();
//客户端ping间隔时间
public static int pingInterval;
public static bool isUsePing = true;
/// <summary>
/// 启动服务器
/// </summary>
/// <param name="port"></param>
public static void StartLoop(int port,bool isPing=true,int pingTime = 30)
{
pingInterval = 30;
isUsePing = isPing;
pingInterval = pingTime;
listenfd = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint endPoint = new IPEndPoint(ip,port);
listenfd.Bind(endPoint);
listenfd.Listen(0);
Console.WriteLine("服务器启动成功:"+DateTime.Now.ToString());
while (true)
{
ResetCheckRead();
Socket.Select(checkRead,null,null,1000);
for (int i = checkRead.Count-1; i >=0; i--)
{
Socket item = checkRead[i];
if (item==listenfd)
{
//服务端收到请求连接
ReadListenfd(listenfd);
}
else
{
//客户端发来消息
ReadClientfd(item);
}
}
OnTimer();
}
}
public static void ResetCheckRead()
{
checkRead.Clear();
checkRead.Add(listenfd);
foreach (ClientState item in clients.Values)
{
checkRead.Add(item.socket);
}
}
//读取Listenfd
public static void ReadListenfd(Socket listenfd)
{
try
{
Socket clientfd = listenfd.Accept();
Console.WriteLine("Accept :"+clientfd.RemoteEndPoint.ToString());
ClientState state = new ClientState();
state.socket = clientfd;
state.lastPingTime = GetTimeSpan();
clients.Add(clientfd,state);
}
catch (Exception ex)
{
Console.WriteLine("Accept Fail:" + ex.ToString());
}
}
//读取Clientfd
public static void ReadClientfd(Socket clientfd)
{
ClientState state = clients[clientfd];
try
{
int count = clientfd.Receive(state.readBuff,state.buffCount,state.capacity-state.buffCount,0);
state.buffCount += count;
if (count<=0)
{
//TODO:关闭连接 分发事件
Close(state);
}
}
catch (SocketException ex)
{
Console.WriteLine("Recive Exception:"+ex.ToString());
Close(state);
}
OnReciveData(state);
}
/// <summary>
/// 解析协议(处理粘包半包 长度信息法)
/// </summary>
/// <param name="state"></param>
private static void OnReciveData(ClientState state)
{
Console.WriteLine("Recv:"+Encoding.UTF8.GetString(state.readBuff));
byte[] readBuff = state.readBuff;
if (state.buffCount<=2)
{
return;
}
Int16 bodyLen = Convert.ToInt16(readBuff[1] << 8 | readBuff[0]);
if (state.buffCount<bodyLen+2)
{
return;
}
int protoNameLen = 0;
string protoName = MsgBase.DecodeProtoName(readBuff,2,out protoNameLen);
MsgBase msg = MsgBase.Decode(protoName,readBuff,2+protoNameLen, bodyLen- protoNameLen);
//处理消息
MethodInfo method = typeof(MsgHandler).GetMethod("On"+protoName);
if (method!=null)
{
object[] param = { state, msg };
method.Invoke(null,param);
}
else
{
Console.WriteLine("OnReciveData Invoke Fail:"+protoName);
}
int start = 2+bodyLen;
int count = state.buffCount - start;
Array.Copy(state.readBuff,start,state.readBuff,0,count);
state.buffCount -= start;
OnReciveData(state);
}
/// <summary>
/// 关闭连接
/// </summary>
public static void Close(ClientState state)
{
MethodInfo method = typeof(EventHandler).GetMethod("OnDisconnect");
if (method==null)
{
Console.WriteLine("Close EventHandler Fun null:OnDisconnect");
}
else
{
object[] prarm = { state };
method.Invoke(null, prarm);
}
state.socket.Close();
clients.Remove(state.socket);
state.socket.Dispose();
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="state"></param>
/// <param name="msg"></param>
public static void SendMsg(ClientState state , MsgBase msg)
{
if (state.socket==null||!state.socket.Connected)
{
return;
}
byte[] protoBytes = MsgBase.EncodeProtoName(msg.protoName);
byte[] bodyBytes = MsgBase.Encode(msg);
byte[] sendData = new byte[protoBytes.Length+ bodyBytes.Length+2];
int totalLen = protoBytes.Length + bodyBytes.Length;
sendData[0] = Convert.ToByte(totalLen % 256);
sendData[1] = Convert.ToByte(totalLen / 256);
Array.Copy(protoBytes,0,sendData,2,protoBytes.Length);
Array.Copy(bodyBytes, 0, sendData, protoBytes.Length+2, bodyBytes.Length);
lock (state.sendQueue)
{
state.sendQueue.Enqueue(sendData);
}
byte[] data = state.sendQueue.Peek();
try
{
state.socket.BeginSend(data, 0, data.Length, 0, OnSendCallBack, state.socket);
}catch(SocketException ex)
{
Console.WriteLine("SendMsg Fail:"+ex.ToString());
}
}
/// <summary>
/// 发送消息回调
/// </summary>
/// <param name="asyncResult"></param>
private static void OnSendCallBack(IAsyncResult asyncResult)
{
Socket socket = asyncResult.AsyncState as Socket;
ClientState state = clients[socket];
try
{
int count = socket.EndSend(asyncResult);
byte[] ba = state.sendQueue.Peek();
if (count == ba.Length)
{
lock (state.sendQueue)
{
state.sendQueue.Dequeue();
ba = state.sendQueue.Count > 0 ? state.sendQueue.Peek() : null;
}
}
if (ba!=null)
{
socket.BeginSend(ba, 0, ba.Length, 0, OnSendCallBack, socket);
}
}
catch (SocketException ex)
{
Console.WriteLine("OnSendCallBack Fail:"+ex.ToString());
}
}
/// <summary>
/// 检测断线
/// </summary>
private static void OnTimer()
{
if (!isUsePing)
{
return;
}
long nowts = GetTimeSpan();
foreach (ClientState item in clients.Values)
{
if (nowts - item.lastPingTime>pingInterval*4)
{
Console.WriteLine("Ping Close:"+item.socket.RemoteEndPoint.ToString());
Close(item);
return;
}
}
}
public static long GetTimeSpan()
{
TimeSpan timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0);
return Convert.ToInt64(timeSpan.TotalSeconds);
}
}
}
连接数据库 DBMananger
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using MySql.Data.MySqlClient;
namespace SeverManager
{
public class DBManager
{
public static MySqlConnection mySql;
/// <summary>
/// 连接数据库
/// </summary>
/// <param name="db"></param>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <param name="user"></param>
/// <param name="pw"></param>
/// <returns></returns>
public static bool ConnectDB(string db,string ip,int port,string user,string pw)
{
mySql = new MySqlConnection();
//连接参数
string connectStr = string.Format("Database={0};Data Source={1};Port={2};User Id={3};Password={4};", db,ip,port,user,pw);
mySql.ConnectionString = connectStr;
try
{
mySql.Open();
Console.WriteLine("【数据库】connect success!");
return true;
}
catch (Exception ex)
{
Console.WriteLine("【数据库】Connect Fail:"+ex.Message);
return false;
}
}
/// <summary>
/// 判断是否是安全字符串
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static bool IsSafeString(string str)
{
if (string.IsNullOrEmpty(str))
{
return true;
}
return !Regex.IsMatch(str,@"[-|;|,|.|\/|\(|\)|\{|\}|%|@|\*|!|\']");
}
/// <summary>
/// 判断是否存在用户
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static bool IsAccountExist(string col,string val)
{
//防止SQL注入
if (!DBManager.IsSafeString(val))
{
Console.WriteLine("【数据库】IsAccountExist: Id is not safe");
return false;
}
if (!DBManager.IsSafeString(col))
{
Console.WriteLine("【数据库】IsAccountExist: col is not safe");
return false;
}
//sql语句
string sqlStr = string.Format("select * from account where {0} = '{1}'", col.Trim(), val.Trim());
try
{
MySqlCommand command = new MySqlCommand(sqlStr, mySql);
MySqlDataReader dataReader = command.ExecuteReader();
bool hasRow = dataReader.HasRows;
dataReader.Close();
return hasRow;
}catch(Exception ex)
{
Console.WriteLine("【数据库】IsAccountExist ERR:"+ex.Message);
return false;
}
}
/// <summary>
/// 注册用户
/// </summary>
/// <param name="account">用户信息</param>
public static bool Register(Account account)
{
if (!IsSafeString(account.Id))
{
Console.WriteLine("【数据库】Register: Id is not safe");
return false;
}
if (!IsSafeString(account.PassWord))
{
Console.WriteLine("【数据库】Register: Password is not safe");
return false;
}
if (!IsSafeString(account.NickName))
{
Console.WriteLine("【数据库】Register: NickName is not safe");
return false;
}
if (IsAccountExist("Id",account.Id))
{
Console.WriteLine("【数据库】Register faiil:已存在用户 id:"+account.Id);
return false;
}
try
{
string s =string.Format("insert into account set Id='{0}',PassWord='{1}',NickName='{2}',CreateTime = '{3}'",account.Id,account.PassWord,account.NickName,DateTime.Now);
using (MySqlCommand cmd = new MySqlCommand(s, mySql))
{
cmd.ExecuteNonQuery();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine("【数据库】Register ERR:"+ex.Message);
return false;
}
}
/// <summary>
/// 创建角色信息
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static bool CreatePlayerData(string id)
{
if (!IsSafeString(id))
{
Console.WriteLine("【数据库】CreatePlayerData fail: Id is not safe");
return false;
}
if (!IsAccountExist("Id",id))
{
Console.WriteLine("【数据库】CreatePlayerData fail: 不存在账号信息 "+id);
return false;
}
try
{
string s = string.Format("insert into PlayerData set PlayerId='{0}',Coins={1},PlayerLevel={2},PlayerDesc='{3}'",id.Trim(),0,1,"");
using (MySqlCommand cmd = new MySqlCommand(s, mySql))
{
cmd.ExecuteNonQuery();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine("【数据库】CreatePlayerData ERR:"+ ex.Message);
return false;
}
}
/// <summary>
/// 检查用户名密码
/// </summary>
/// <param name="id"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public static bool CheckPassword(string id,string pwd)
{
if (!IsSafeString(id))
{
Console.WriteLine("【数据库】CheckPassword:id is not safe");
return false;
}
if (!IsSafeString(pwd))
{
Console.WriteLine("【数据库】CheckPassword:pwd is not safe");
return false;
}
try
{
string s = string.Format("select * from Account where Id='{0}' and Password='{1}'",id.Trim(),pwd.Trim());
MySqlCommand cmd = new MySqlCommand(s,mySql);
MySqlDataReader data = cmd.ExecuteReader();
bool hasrows = data.HasRows;
data.Close();
return hasrows;
}
catch (Exception ex)
{
Console.WriteLine("【数据库】CheckPassword ERR:"+ex.Message);
return false;
}
}
/// <summary>
/// 获取玩家数据
/// </summary>
/// <param name="id">用户id</param>
/// <returns></returns>
public static PlayerData GetPlayerData(string id)
{
if (!IsSafeString(id))
{
Console.WriteLine("【数据库】GetPlayerData fail:id isnot safe");
return null;
}
string s = string.Format("select * from PlayerData where PlayerId = '{0}'", id.Trim());
try
{
MySqlCommand cmd = new MySqlCommand(s,mySql);
MySqlDataReader data = cmd.ExecuteReader();
if (!data.HasRows)
{
return null;
}
data.Read();
string plyaerId = data["PlayerId"].ToString();
int coins = Convert.ToInt32(data["Coins"]);
int levl = Convert.ToInt32(data["PlayerLevel"]);
string playerDesc = data["PlayerDesc"].ToString();
PlayerData playerData = new PlayerData(plyaerId,coins,levl,playerDesc);
data.Close();
return playerData;
}
catch (Exception ex) {
Console.WriteLine("【数据库】GetPlayerData ERR:"+ex.Message);
return null;
}
}
/// <summary>
/// 更新用户数据
/// </summary>
/// <param name="playerData"></param>
/// <returns></returns>
public static bool UpdatePlayerData(PlayerData playerData)
{
try
{
string s = string.Format("update PlayerData set Coins = {0},PlayerLevel = {1},PlayerDesc='{2}' where PlayerId={3}",playerData.Coins,playerData.PlayerLevel,playerData.PlayerDesc);
using (MySqlCommand cmd = new MySqlCommand(s, mySql))
{
cmd.ExecuteNonQuery();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine("【数据库】UpdatePlayerData ERR:" + ex.Message) ;
return false;
}
}
}
}
角色管理 PlayerManger
using System;
using System.Collections.Generic;
using System.Text;
namespace SeverManager
{
public class PlayerManager
{
private static Dictionary<string, Player> PlayerDic = new Dictionary<string, Player>();
/// <summary>
/// 添加角色
/// </summary>
/// <param name="player"></param>
public static void AddPlayer(Player player)
{
if (!PlayerDic.ContainsKey(player.Id))
{
PlayerDic.Add(player.Id,player);
}
}
/// <summary>
/// 移除角色
/// </summary>
/// <param name="id"></param>
public static void RemovePlayer(string id)
{
if (PlayerDic.ContainsKey(id))
{
PlayerDic.Remove(id);
}
}
/// <summary>
/// 获取角色ById
/// </summary>
/// <param name="id"></param>
public static Player GetPlayerById(string id)
{
return PlayerDic[id];
}
/// <summary>
/// 是否在线
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static bool IsOnline(string id)
{
return PlayerDic.ContainsKey(id);
}
}
}
服务端 MsgBase 协议基类
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
namespace SeverManager
{
public class MsgBase
{
public string protoName;
public MsgBase(string protoName)
{
this.protoName = protoName;
}
public static byte[] Encode(MsgBase msg)
{
byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(msg));
return bytes;
}
public static MsgBase Decode(string protoName, byte[] bytes, int offset, int count)
{
string s = Encoding.UTF8.GetString(bytes,offset,count);
Type type = Type.GetType("SeverManager." + protoName);
MsgBase msg =(MsgBase) JsonConvert.DeserializeObject(s, type);
return msg;
}
public static byte[] EncodeProtoName(string protoName)
{
byte[] nameBy = Encoding.UTF8.GetBytes(protoName);
byte[] ret = new byte[2+nameBy.Length];
ret[0] = Convert.ToByte(nameBy.Length % 256);
ret[1] = Convert.ToByte(nameBy.Length / 256);
Array.Copy(nameBy,0,ret,2,nameBy.Length);
return ret;
}
public static string DecodeProtoName(byte[] data , int offset , out int count)
{
count = 0;
if (offset+2>=data.Length)
{
return "";
}
int len = data[offset + 1] << 8 | data[offset];
if (len<=0)
{
count = 2;
return "";
}
count = len + 2;
string s = Encoding.UTF8.GetString(data,offset+2,len);
return s;
}
}
}
ClientState 服务端监听的客户端状态
using iTextSharp.text.pdf.qrcode;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
namespace SeverManager
{
public class ClientState
{
public int capacity = 1024;
public Socket socket;
public byte[] readBuff;
public int buffCount = 0;
public Queue<byte[]> sendQueue;
public long lastPingTime;
public Player player;
public ClientState()
{
readBuff = new byte[capacity];
sendQueue = new Queue<byte[]>();
}
}
}
网友评论