-
通用服务端框架,具有粘包半包处理、协议解析等功能,服务端使用多路复用,单进程单线程
-
网络相关代码
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;
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);
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)
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;
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;
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;
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;
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
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);
//客户端发来消息
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)
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];
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);
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");
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();
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];
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;
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());
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;
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;
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;
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());
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)
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[]>();