感觉之前的聊天功能可能有一些缺陷,今天收到书华兄的启发,发表一些感慨,C# .net高手跟新手的区别就是,新手仅仅满足功能上的实现,而很少去考虑性能上的问题,比如高并发怎么处理,打个比方,新手做完聊天功能之后,会沾沾自喜,而不考虑最大客户连接有多少,做个实验,如果连续有四个左右的客户端同时连接到服务器端,服务器就要消耗将近200M的内存,这时机器可怕的事情,如果不做处理的话,假设几百人去连接,估计服务器端就要崩溃了,还有一点高手喜欢写封装,将功能进行高度封装给新手用,新手用完了人家封装的类库,然后简单代码就实现功能了,也会沾沾自喜,津津乐道,这样就会止步不前!用了一下封装的类库来写unity聊天客户端果真非常快,几行代码就搞定!

unity客户端:

UI:

using UnityEngine; using System.Collections;  public class chart : MonoBehaviour {  	string txtmsg = ""; 	public string txtServer = "192.168.1.24"; 	string txtLog = ""; 	public string txtPort = "50000"; 	ClientLibrary.Client client; 	ClientLibrary.Model model = new ClientLibrary.Model(); 	// Use this for initialization 	void Start () { 	 	}  	bool flag = true; 	// Update is called once per frame 	void Update () { 		if(client.HeartDataSend()!=1) 		{ 			SetTxt("请检查网络你已经掉线,可能原因服务器出错,请重新连接"); 			client.KillSocket(); 			flag = false; 		} 	}  	void OnGUI() 	{ 		txtServer = GUI.TextField(new Rect(10f,20f,100f,20f),txtServer); 		txtLog = GUI.TextField (new Rect(50f,40f,200f,200f),txtLog); 		if(GUI.Button(new Rect(120f,20f,50f,20f),"start")&&flag) 		{ 			model.TxtServer = txtServer; 			model.TxtPort = txtPort; 			bool enable; 			client = new ClientLibrary.Client(model,SetTxt,out enable); 			if(enable) 			{ 				//txtLog = "123"; 			} 			else 			{ 				//txtLog = "no"; 			} 			flag = false; 		} 	} 	void SetTxt(string msg) 	{ 		txtLog+=msg+"\r\n"; 	} }

ChatClient:

using System.Net.Sockets; using System.Text; using System.Threading;  namespace ClientLibrary {     #region 委托     /// <summary>     /// 信息显示委托     /// </summary>     /// <param name="msg">需要打印到前台的信息</param>     public delegate void deMessageShow(string msg);     /// <summary>     /// 文件保存委托     /// </summary>     /// <param name="buffer">保存的文件数据</param>     /// <param name="count">文件大小</param>     /// <returns></returns>     public delegate bool deGetFileStream(byte[] buffer,int count);     /// <summary>     /// 客户端震动 委托     /// </summary>     public delegate void deZD();     #endregion     /// <summary>     /// 客户端实体类     /// </summary>     public class Model     {         private string txtMsg;          public string TxtMsg         {             get { return txtMsg; }             set { txtMsg = value; }         }         private string txtPort;          public string TxtPort         {             get { return txtPort; }             set { txtPort = value; }         }        private string txtServer;          public string TxtServer         {             get { return txtServer; }             set { txtServer = value; }         }     }     /// <summary>     /// 客户端方法类     /// </summary>     public class Client     {         public Client(Model model,deMessageShow messageShowFun,out bool enable)         {             messageShow = messageShowFun;             lastTimeRecive = DateTime.Now;             if (CreateClientSocket(model)) //创建Socket             {                 enable = true;                 return;             }             enable = false;              }         public Client(Model model, deMessageShow message, deGetFileStream saveFileFun, out bool enable)         {             messageShow = message;             getFileStream = saveFileFun;             lastTimeRecive = DateTime.Now;              if (CreateClientSocket(model))//创建Socket             {                 enable = true;                 return;             }              enable = false;         }         public Client(Model model, deMessageShow message, deGetFileStream saveFileFun, deZD zdFun, out bool enable)         {             messageShow = message;             getFileStream = saveFileFun;             lastTimeRecive = DateTime.Now;               if (!CreateClientSocket(model)) //创建Socket             {                 enable = true;                 return;             }               enable = false;         }         Model model = new Model();         /// <summary>         ///  通信Scoket         /// </summary>         Socket connSocket;         /// <summary>         /// 通信线程         /// </summary>         Thread thmsg;         /// <summary>         /// 最后一次接受数据时间         /// </summary>         public DateTime lastTimeRecive;         /// <summary>         /// 最后一次发送数据时间         /// </summary>         public DateTime lastTimeSend;         #region 声明委托      public   deMessageShow messageShow;       public  deGetFileStream getFileStream;      public   deZD zD;         #endregion          /// <summary>         /// 创建客户端Socket         /// </summary>         /// <param name="ModelUI"></param>         /// <returns>创建状态</returns>         public bool CreateClientSocket(Model ModelUI)         {             model = ModelUI;             bool enabel = false;              //服务器IP             IPAddress ipServer = IPAddress.Parse(model.TxtServer);             //创建 终端地址             IPEndPoint endPointServer = new IPEndPoint(ipServer, int.Parse(model.TxtPort));             //创建 连接socket connSocket            connSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);             try             {                 connSocket.Connect(endPointServer);                 messageShow("登陆成功");                 #region  创建接受信息的线程                 thmsg = new Thread(ReciveMsg);                 thmsg.IsBackground = true;                 thmsg.Start();                 #endregion             }             catch (Exception ex)             {                 messageShow(ex.Message);                enabel= true;             }             return enabel;         }          /// <summary>         /// 信息接收         /// </summary>         private void ReciveMsg()         {             //0 文字 1 文件 2 震动             byte[] buffer = new byte[5 * 1024 * 1024];             while (true)             {                 int count = connSocket.Receive(buffer);                 int flag = buffer[0];                 if (count == 0)                 {                     connSocket.Close();                     messageShow("你掉线或者服务器关系");                     break;                 }                 Recive(buffer, count, flag);             }         }          #region 必要方法         #region 接收+Recive(byte[] buffer, int count,int flag)         /// <summary>         /// 处理接受的信息         /// </summary>         /// <param name="buffer"></param>         /// <param name="count"></param>         /// <param name="flag"></param>         private void Recive(byte[] buffer, int count, int flag)         {             if (flag == 0)             {                 #region flag=0 文字信息                 string msg = Encoding.UTF8.GetString(buffer, 1, count - 1);                 messageShow("服务器 : " + msg);                 #endregion             }             else if (flag == 1)             {                 #region flag=1 传送文件                 if (getFileStream(buffer,count))                 {                     messageShow("接受完成");                 }                            #endregion             }             else if (flag == 2)             {                 #region flag=2 震动                 zD();                 #endregion             }             else if (flag == 3)             {                 string atat=Encoding.UTF8.GetString(buffer,1,count-1);                 if (atat == "ATAT")                 {                     lastTimeRecive = DateTime.Now;                 }             }         }           #endregion         /// <summary>         /// 发送心跳包         /// </summary>         /// <returns>发送状态</returns>         public int HeartDataSend()         {             lastTimeSend = DateTime.Now;             if (DateTime.Now.Second - lastTimeRecive.Second > 3)             {                 return 3;             }             if (connSocket != null && connSocket.Connected)             {                 try                 {                     byte[] buffer = Encoding.UTF8.GetBytes("NTNT");                     connSocket.Send(buffer);                     lastTimeRecive = DateTime.Now;                     return 1;                 }                 catch (Exception ex)                 {                    // messageShow(ex.Message);                     return 2;                 }             }             return 1;         }         /// <summary>         /// 数据发送         /// </summary>         /// <returns></returns>         public bool Send()         {             if (connSocket != null && connSocket.Connected)             {                 try                 {                     byte[] buffer = new byte[1024 * 1024 * 5];                     buffer = Encoding.UTF8.GetBytes(model.TxtMsg);                     connSocket.Send(buffer);                     lastTimeRecive = DateTime.Now;                     return true;                 }                 catch (Exception ex)                 {                     messageShow(ex.Message);                     return false;                 }             }             return false;         }          /// <summary>         /// 终止连接         /// </summary>         public void KillSocket()         {             if (thmsg != null)             {                 thmsg.Abort();             }             if (connSocket != null && connSocket.Connected)             {                 connSocket.Shutdown(SocketShutdown.Both);                 connSocket.Close();             }         }         #endregion     } }

服务器端:

Server:

using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading;  namespace ServerChatClass {     #region 委托     /// <summary>     /// 信息显示委托     /// </summary>     /// <param name="msg">需要打印到前台的信息</param>     public delegate void deMessageShow(string msg);     /// <summary>     /// 注册客户端ednpoing和Socket,Thread     /// </summary>     /// <param name="endpoing">注册地址</param>     public delegate void deRegisterClientIP(string endpoing);     /// <summary>     /// 从UI上移除客户端显示     /// </summary>     /// <param name="endpoing">客户端地址或者名称</param>     public delegate void deRemoveClientIPFromUI(string endpoing);     #endregion     /// <summary>     /// 实体类     /// </summary>     public class Model     {         private string txtMsg;         private string txtPath;          private string txtLog;         private string txtServer;         private string txtPort;          private string clientEndPoint;         /// <summary>         /// 客户端地址         /// </summary>         public string ClientEndPoint         {             get { return clientEndPoint; }             set { clientEndPoint = value; }         }         /// <summary>         /// 端口         /// </summary>         public string TxtPort         {             get { return txtPort; }             set { txtPort = value; }         }         /// <summary>         /// IP         /// </summary>         public string TxtServer         {             get { return txtServer; }             set { txtServer = value; }         }         /// <summary>         /// 日志         /// </summary>         public string TxtLog         {             get { return txtLog; }             set { txtLog = value; }         }         /// <summary>         /// 文件地址         /// </summary>         public string TxtPath         {             get { return txtPath; }             set { txtPath = value; }         }         /// <summary>         /// 消息文字发送         /// </summary>         public string TxtMsg         {             get { return txtMsg; }             set { txtMsg = value; }         }      }     public class Request     {         public Request(string msg)         {             if (msg.Length < 100)             { return; }             try             {                 string[] lines = msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);                 string firstLine = lines[0];                 string[] array = firstLine.Split(' ');                 method = array[0];                 url = array[1];             }             catch (Exception)             {              }          }         private string method;         public string Method         {             get { return method; }             set { method = value; }         }         private string url;         public string Url         {             get { return url; }             set { url = value; }         }     }     public class SeverChar     {          #region 客户机注册字典         /// <summary>         /// 客户端地址clientIP和对应最后一次通信时间         /// </summary>         public Dictionary<string, DateTime> dicListTimeConnSocket = new Dictionary<string, DateTime>();         /// <summary>         /// 客户端地址clinetIP和对应的通信Socket         /// </summary>         public Dictionary<string, Socket> dicConnSocket = new Dictionary<string, Socket>();         /// <summary>         /// 客户端地址clientIP和对应通信线程ThreadMsg         /// </summary>         public Dictionary<string, Thread> dicThreadMsg = new Dictionary<string, Thread>();         #endregion         #region 委托声明         /// <summary>         /// 消息显示         /// </summary>         public deMessageShow messageShow;         /// <summary>         /// 注册客户机         /// </summary>         public deRegisterClientIP registerClientIP;         /// <summary>         /// 从UI上移除客户端显示         /// </summary>         public deRemoveClientIPFromUI removeClientIPFromUI;         #endregion         /// <summary>         /// 初始化程序         /// </summary>         /// <param name="downline">掉线信息</param>          public SeverChar(string msg,Model model, deMessageShow messageShowFun, string downline, out bool enable)         {             messageShow = messageShowFun;             if (CreateServerMonitorSorcket(model,msg)) //创建Socket             {                 enable = true;             }             else             {                 enable = false;             }         }         public SeverChar(string msg,Model model, deMessageShow messageShowFun,deRegisterClientIP registerClientIPFun ,string downline, out bool enable)         {             registerClientIP = registerClientIPFun;             messageShow = messageShowFun;             if (CreateServerMonitorSorcket(model, msg))//创建Socket             {                 enable = true;             }             else             {                 enable = false;             }         }         public SeverChar(string msg,Model model, deMessageShow messageShowFun, deRegisterClientIP registerClientIPFun, deRemoveClientIPFromUI removerClientIPFormUIFun,string downline, out bool enable)         {             removeClientIPFromUI = removerClientIPFormUIFun;             registerClientIP = registerClientIPFun;             messageShow = messageShowFun;             if (CreateServerMonitorSorcket(model, msg)) //创建Socket             {                 enable = true;             }             else             {                 enable=false;             }         }         public SeverChar(string downline)         {             downLine = downline;         }         /// <summary>         /// 需要发送请求的通信Socket         /// </summary>         public List<Socket> listSendConnSocket = new List<Socket>();         /// <summary>         /// 掉线信息提示         /// </summary>         public string downLine;         Socket socketServer;//监听socket         Model modelSever = new Model();         object o = new object();          #region 创建监听的socket socketServer+public bool CreateServerMonitorSorcket(Model model, string msg)         /// <summary>         /// 服务器创建监听的socket socketServer         /// </summary>         /// <param name="model">监听实体,包含监听端口和IP</param>         /// <param name="msg">监听成功后显示的信息</param>         /// <returns></returns>         public bool CreateServerMonitorSorcket(Model model, string msg)         {             modelSever = model;             bool enable;             Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);             #  region 其他测试             //IPHostEntry host = new IPHostEntry();             //host.             #endregion             //Ip地址             IPAddress ipServer = IPAddress.Parse(model.TxtServer);             //ip地址和端口             IPEndPoint endPointServer = new IPEndPoint(ipServer, int.Parse(model.TxtPort));             try             {                 //绑定网络端点                 socketServer.Bind(endPointServer);                 //设置排队长度                 socketServer.Listen(10);                 messageShow(msg);                 #region 用连接连接线程ThreadConnSockt  创建通信Socket 防止阻塞卡死+Listen(object)                 Thread threadConnSocket = new Thread(Listen);                 threadConnSocket.Name = "conn";                 threadConnSocket.IsBackground = true;                 threadConnSocket.Start(socketServer);                 #endregion                 enable = true;             }             catch (Exception ex)             {                 messageShow(ex.Message);                 enable = false;             }             return enable;         }         #endregion          #region 创建服务端通信Socket  connSocket单线程会阻塞窗体运行+Listen(object)         /// <summary>         /// 创建通信Socket         /// </summary>         /// <param name="socket"></param>         public void Listen(object socket)         {             socketServer = socket as Socket;             while (true)             {                 Socket connSocket = socketServer.Accept();//阻塞等待 客户端连接                 string clinetEndPing = connSocket.RemoteEndPoint.ToString();//获取客户端通信地址                 messageShow(clinetEndPing+"登陆");                 #region 新建通信监听线程threadMsg 接收客户端发送过来的信息                 Thread threadMsg = new Thread(ReciveMsg);                              threadMsg.Name = "msg";                 threadMsg.IsBackground = true;                 threadMsg.Start(connSocket);                 RegisterClientAtSever(clinetEndPing, threadMsg, connSocket);                 #endregion             }         }         #endregion         #region 接收客户端发送的信息 ReciveMsg(object socket)         /// <summary>         /// 接收客户端发送的信息 方法         /// </summary>         /// <param name="socket">发送信息的socket</param>         public void ReciveMsg(object socket)         {             Socket connSocket = socket as Socket;             string clineteEndPoint = connSocket.RemoteEndPoint.ToString();             byte[] buffer = new byte[1024 * 1024 * 5];             while (true)             {                 int count = connSocket.Receive(buffer);//阻塞等待输入 当count=0 说明连接关闭                 if (count == 0)                 {                     dicConnSocket[clineteEndPoint].Close();                     messageShow(clineteEndPoint + downLine);                     RemoveClient(clineteEndPoint);                 }                 dicListTimeConnSocket[clineteEndPoint] = DateTime.Now;//有消息传入                 #region 协议解析                 string ntnt = Encoding.UTF8.GetString(buffer, 0, 4);                 if (ntnt != "NTNT")//不是心跳报就显示                 {                     string msg = Encoding.UTF8.GetString(buffer, 0, count);                     messageShow(clineteEndPoint + " : \r\n      " + msg);                 }                 #endregion                 else                 {                     lock (o)                     {                         List<Socket> listSendConnSocket = new List<Socket>();                         listSendConnSocket.Add(dicConnSocket[clineteEndPoint]);                         SendStreamFunction(listSendConnSocket, 3, modelSever);                         listSendConnSocket.Clear();                     }                 }             }         }         #endregion          #region 发送方法+public void SendStreamFunction(List<Socket> listSendConnSocket, int flag, Model model)         /// <summary>         /// 发送方法         /// </summary>         /// <param name="listSendConnSocket"></param>         /// <param name="flag"></param>         /// <param name="model"></param>         public void SendStreamFunction(List<Socket> listSendConnSocket, int flag, Model model, params byte[] buffersend)         {             if (listSendConnSocket.Count > 0)             {                 List<byte> list = new List<byte>();                 if (flag == 0)                 {                     byte[] buffer = new byte[5 * 1024 * 1024];                     buffer = Encoding.UTF8.GetBytes(model.TxtMsg);                     list.Add(0);//协议 0 文字                     list.AddRange(buffer);                 }                 else if (flag == 1)                 {                     if (model.TxtPath != null)                     {                         using (FileStream fs = new FileStream(model.TxtPath, FileMode.Open, FileAccess.Read))                         {                             byte[] buffer = new byte[fs.Length];                             fs.Read(buffer, 0, buffer.Length);                             list.Add(1);//协议 1 文件                             list.AddRange(buffer);                         }                     }                 }                 else if (flag == 2)                 {                     list.Add(2);                 }                 else if (flag == 3)//没有收到任何通信的协议 一定时间  协议3                 {                     byte[] buffer = Encoding.UTF8.GetBytes("ATAT");//NTNT心跳报                     list.Add(3);                     list.AddRange(buffer);                 }                 else if (flag == 4)                 {                     if (buffersend != null)                     {                         list.AddRange(buffersend);                     }                 }                 foreach (Socket item in listSendConnSocket)                 {                     item.Send(list.ToArray());                 }             }          }         #endregion          #region 定时检测方法+public  void Timer()         /// <summary>         /// 定时检测通信状态         /// </summary>         public void Timer()         {             int index = 0;             Dictionary<int, string> dic = new Dictionary<int, string>();             foreach (KeyValuePair<string, DateTime> item in dicListTimeConnSocket)             {                 dic.Add(index, item.Key);                 index++;             }             DateTime timeNow = DateTime.Now;             for (int i = 0; i < dicListTimeConnSocket.Count; i++)             {                 if (timeNow.Second - dicListTimeConnSocket[dic[i]].Second > 3)                 {                     RemoveClient(dic[i]);                 }             }          }         #endregion          #region 客户端在服务器注册+public void RegisterClientAtSever(string endPoint, Thread threadMsg, Socket connSocket)         /// <summary>         /// 客户端注册         /// </summary>         /// <param name="endPoint">客户端地址</param>         /// <param name="threadMsg">通信线程</param>         /// <param name="connSocket">通信Socket</param>         public void RegisterClientAtSever(string endPoint, Thread threadMsg, Socket connSocket)         {             dicThreadMsg.Add(endPoint, threadMsg);             dicConnSocket.Add(endPoint, connSocket);             modelSever.ClientEndPoint = endPoint;             if (registerClientIP != null)             {                 registerClientIP(endPoint);//注册显示到 用户UI上 通过委托 registerClientIP             }         }         #endregion         #region 从服务器注销客户端连接+RemoveClient(string clinetEndPoint)         /// <summary>         /// 从服务器注销客户端连接         /// </summary>         /// <param name="clinetEndPoint"></param>         public void RemoveClient(string clinetEndPoint)         {             KillClient(clinetEndPoint);             dicThreadMsg.Remove(clinetEndPoint);             dicConnSocket.Remove(clinetEndPoint);             dicListTimeConnSocket.Remove(clinetEndPoint);             if (removeClientIPFromUI != null)             {                 removeClientIPFromUI(clinetEndPoint);             }         }         #endregion         #region 终止客户端通信+public void KillClient(string clinetEndPoint)         /// <summary>         /// 终止客户端通信         /// </summary>         /// <param name="clinetEndPoint"></param>         public void KillClient(string clinetEndPoint)         {             if (dicConnSocket[clinetEndPoint].Connected)             {                 dicConnSocket[clinetEndPoint].Shutdown(SocketShutdown.Both);             }             dicConnSocket[clinetEndPoint].Close();             dicThreadMsg[clinetEndPoint].Abort();         }         #endregion     } } 

ServerWinform:

using System; using System.Collections.Generic; using System.Threading; using System.Windows.Forms; using ServerChatClass;  namespace ChatServer {     public partial class ServerChar : Form     {         public ServerChar()         {             InitializeComponent();             Control.CheckForIllegalCrossThreadCalls = false;         }          //Socket connSocket;//通信socket         //  Thread thmsg;//接收消息 线程          ServerChatClass.SeverChar severchar;         Model model = new Model();          private void btnStart_Click(object sender, EventArgs e)         {             bool enable;             model.TxtServer = txtServer.Text;             model.TxtPort = txtPort.Text;             severchar = new SeverChar("开始监听",model, ShowLog, add, RemoveControl, "掉线",out enable);             if (enable)             {                 btnStart.Enabled = false;                 timer1.Start();             }             else             {                 btnStart.Enabled = true;             }         }         void add(string clinetIP)         {             listIp.Items.Add(clinetIP);             cboUsers.Items.Add(clinetIP);         }         public void ShowLog(string msg)         {             txtLog.AppendText(msg + "\r\n");         }         #region 发送         private void Send(object sender, EventArgs e)         {             int flag = 0;             Button btn = sender as Button;             if (btn.Text == "发送消息")             {                 model.TxtMsg = txtMsg.Text;                 flag = 0;             }             else if (btn.Text == "发送文件")             {                 model.TxtPath = txtPath.Text;                 flag = 1;             }             else if (btn.Text == "震动")             {                 flag = 2;             }             severchar.SendStreamFunction(severchar.listSendConnSocket, flag, model);         }         //private void SendMsg(object sender, EventArgs e)         //{          //}         //private void btnSendFile_Click(object sender, EventArgs e)         //{         //    model.TxtPath = txtPath.Text;         //    severchar.SendStreamFunction(severchar.listSendConnSocket, 1, model);         //}         //private void btnZD_Click(object sender, EventArgs e)         //{         //    severchar.SendStreamFunction(severchar.listSendConnSocket, 2, model);         //}         #endregion         private void btnSelect_Click(object sender, EventArgs e)         {             OpenFileDialog open = new OpenFileDialog();             if (open.ShowDialog() == System.Windows.Forms.DialogResult.OK)             {                 txtPath.Text = open.FileName;             }         }         private void DownLine_Click(object sender, EventArgs e)         {             for (int i = 0; i < listIp.SelectedItems.Count; i++)             {                 string clinetIP = listIp.SelectedItems[i].ToString();                 severchar.RemoveClient(clinetIP);             }          }         private void RemoveControl(string clinetIP)         {             cboUsers.Items.Remove(clinetIP);             listIp.Items.Remove(clinetIP);         }         private void listIp_SelectedIndexChanged(object sender, EventArgs e)         {             severchar.listSendConnSocket.Clear();             if (listIp.SelectedItems.Count == 1)             {                 cboUsers.SelectedIndex = listIp.SelectedIndex;             }             foreach (string item in listIp.SelectedItems)             {                 severchar.listSendConnSocket.Add(severchar.dicConnSocket[item]);             }         }         private void Server_FormClosing(object sender, FormClosingEventArgs e)         {             if (severchar.dicThreadMsg.Count > 0)             {                 int index = 0;                 Dictionary<int, string> dic = new Dictionary<int, string>();                 foreach (KeyValuePair<string, Thread> item in severchar.dicThreadMsg)                 {                     dic.Add(index, item.Key);                     index++;                 }                 DateTime timeNow = DateTime.Now;                 for (int i = 0; i < severchar.dicThreadMsg.Count; i++)                 {                     severchar.RemoveClient(dic[i]);                                 }             }         }         private void timer1_Tick(object sender, EventArgs e)         {         if(  severchar.dicListTimeConnSocket.Count>0)         {             severchar.Timer();         }               }     } } 


下载:http://download.csdn.net/detail/s10141303/6675157



==================== 迂者 丁小未 CSDN博客专栏=================

MyBlog:http://blog.csdn.net/dingxiaowei2013              MyQQ:1213250243

MyTel:13262983383 

====================== 相互学习,共同进步 ===================