Unity Socket服务器(客户端)通用框架

  • 通用服务端框架,具有粘包半包处理、协议解析等功能,服务端使用多路复用,单进程单线程

客户端

  • 网络相关代码
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[]>();
        }
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335