c#TCP多线程服务器实例代码

来源:互联网 发布:苏轼 文言文徙知 编辑:程序博客网 时间:2024/05/21 14:54




using System;

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.Net.NetworkInformation;


namespace 黄炎培_服务器
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        /// <summary>
        /// 服务器倾听客户端连接线程
        /// </summary>
        Thread threadWatchs = null;


        /// <summary>
        /// 服务器套接字
        /// </summary>
        Socket socketServer = null;


        /// <summary>
        /// 服务器监控客户端连接情况的线程
        /// </summary>
        Thread MonitoThread = null;


        /// <summary>
        /// 客户端ip与套接字的集合
        /// </summary>
        Dictionary<string, Socket> dictSocket = new Dictionary<string, Socket>();


        /// <summary>
        /// 客户端ip与线程的集合
        /// </summary>
        Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();


        /// <summary>
        /// 客户端连接线程的数量 
        /// </summary>
        long numThreadVal = 0;


        /// <summary>
        /// 服务器ip
        /// </summary>
        string strServerIP = "192.168.4.3";


        /// <summary>
        /// 服务器端口
        /// </summary>
        int serverPort = 8080;


        /// <summary>
        /// 缓存数据长度
        /// </summary>
        int receiveDataValLengt = 1024;//缓存区长度


        /// <summary>
        /// 用于Ping客户端
        /// </summary>
        Ping monitoPing = new Ping();


        /// <summary>
        /// 异常断开的客户端
        /// </summary>
        Dictionary<string, string> dictBodClient = new Dictionary<string, string>();


        /// <summary>
        /// 指示释放释放线程
        /// </summary>
        bool isClearThread = false;




        private void Form1_Load(object sender, EventArgs e)
        {
            //开启服务器
            openServer(strServerIP, serverPort);
            //开启服务器监控线程
            MonitoThread = new Thread(monitoThreadsDynamic);
            //后台线程
            MonitoThread.IsBackground = true;
            //启动线程
            MonitoThread.Start();
        }


        /// <summary>
        /// 开始实时监控客户端的连接情况
        /// </summary>
        void monitoThreadsDynamic()
        {
            delegateShowMseeage("开始实时监控客户端连接情况");
            while (true)
            {
                Thread.Sleep(3000);
                try
                {
                    foreach (var vv in dictSocket)
                    {
                        PingReply reply = monitoPing.Send(vv.Key.Split(':')[0],1000);
                        //如果Ping通
                        if (reply.Status == IPStatus.Success)
                        {
                            //表示客户端连接正常
                            delegateShowMseeage("客户端" + vv.Key + "连接正常");
                        }
                        else
                        {
                            //添加异常客户端连接到集合dictBodClient
                            dictBodClient.Add(vv.Key, "old");
                            delegateShowMseeage("客户端" + vv.Key + "连接异常");
                        }
                    }


                    //释放异常连接的线程
                    foreach (var vvv in dictThread)
                    {
                        isClearThread = false;
                        foreach (var vvvv in dictBodClient)
                        {
                            if (vvv.Key == vvvv.Key)
                            {
                                isClearThread = true;
                                break;
                            }
                        }
                        if (isClearThread)
                        {
                            vvv.Value.Abort();
                            delegateShowMseeage("客户端" + vvv.Key + "占用的线程已释放");
                        }
                    }


                    //从集合合中移除异常连接的客户端
                    foreach (var vvv in dictBodClient)
                    {
                        //从集合中移除客户端套接字
                        dictSocket.Remove(vvv.Key);
                        //从集合中移除客户端线程
                        dictThread.Remove(vvv.Key);
                        //从列表中移除客户端套接字的远程终结点
                        deleteClientSocket(vvv.Key);
                        //跨线程显示提示数据
                        delegateShowMseeage("客户端" + vvv.Key + "断开连接");
                    }
                }
                catch (Exception se)
                {
                    //MessageBox.Show(se.Message);
                    delegateShowMseeage(se.Message);
                }


                dictBodClient.Clear();
                //获得当前程序运行的线程总数量
                numThreadVal = Process.GetCurrentProcess().Threads.Count;
                delegateShowMseeage("当前的线程总数量为:" + numThreadVal);
                //获得客户端连接所占用的线程数量
                numThreadVal = dictThread.LongCount();
                //跨线程显示消息
                delegateShowMseeage("其中客户端连接的线程数量为:" + numThreadVal);
            }
        }


        /// <summary>
        /// 开启服务器
        /// </summary>
        /// <param name="serverIP"></param>
        /// <param name="serverPort"></param>
        void openServer(string serverIP, int serverPort)
        {
            //实例化服务器套接字
            socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //配置网络端点
            IPEndPoint ipAndPort = new IPEndPoint(IPAddress.Parse(serverIP), serverPort);
            try
            {
                //设置服务器套接字的连接参数
                socketServer.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                //将网络端点绑定到服务器套接字
                socketServer.Bind(ipAndPort);
            }
            catch (SocketException se)
            {
                MessageBox.Show("异常:" + se.Message);
                return;
            }
            //服务器开始倾听,指定最多客户端数量为10000
            socketServer.Listen(10000);
            //实例化服务器倾听客户端连接的线程
            threadWatchs = new Thread(WatchClientConnecting);
            //后台运行线程
            threadWatchs.IsBackground = true;
            //启动线程
            threadWatchs.Start();
            //显示提示消息
            showMesssge("服务器启动成功");
        }


        /// <summary>
        /// 开始倾听客户端
        /// </summary>
        void WatchClientConnecting()
        {
            //跨线程显示提示消息
            delegateShowMseeage("服务器开始倾听客户端连接");
            while (true)
            {
                //倾听新的客户端连接请求
                Socket newClientConnecting = socketServer.Accept();
                //添加客户端套接字的远程终结点到列表
                addClientSocket(newClientConnecting.RemoteEndPoint.ToString());
                //新建一条新的客户端线程
                Thread newClinetThread = new Thread(receiveData);
                //后台运行客户端
                newClinetThread.IsBackground = true;
                //启动线程,并将 新客户端的套接字 绑定到线程执行的方法
                newClinetThread.Start(newClientConnecting);
                //添加客户端套接字到集合
                dictSocket.Add(newClientConnecting.RemoteEndPoint.ToString(), newClientConnecting);
                //添加客户端接受数据的线程到集合
                dictThread.Add(newClientConnecting.RemoteEndPoint.ToString(), newClinetThread);
                //跨线程显示提示信息
                delegateShowMseeage("新客户端:" + newClientConnecting.RemoteEndPoint.ToString());
            }
        }


        /// <summary>
        /// 接受数据
        /// </summary>
        /// <param name="socketConnecting"></param>
        void receiveData(object socketConnecting)
        {
            //获取该线程绑定的客户端套接字
            Socket socketClient = socketConnecting as Socket;
            while (true)
            {
                //新建一个缓存区
                byte[] receiveDataVal = new byte[receiveDataValLengt];
                //数据长度
                int receiveDataLength = -1;
                try
                {
                    //接受数据填入缓存区并获得数据长度
                    receiveDataLength = socketClient.Receive(receiveDataVal);
                    //接受到数据
                    if (receiveDataLength > 0)
                    {
                        //跨线程显示接受到的数据
                        delegateShowReceiveData(socketClient, receiveDataVal, receiveDataLength);
                        //综合处理接受到的数据
                        receiveDataIntegratedProcessing(receiveDataVal, receiveDataLength);
                    }
                    else
                    {
                        //从集合中移除客户端套接字
                        dictSocket.Remove(socketClient.RemoteEndPoint.ToString());
                        //从集合中移除客户端线程
                        dictThread.Remove(socketClient.RemoteEndPoint.ToString());
                        //从列表中移除客户端套接字的远程终结点
                        deleteClientSocket(socketClient.RemoteEndPoint.ToString());
                        //跨线程显示提示数据
                        delegateShowMseeage("客户端" + socketClient.RemoteEndPoint.ToString() + "断开连接");
                        //释放该线程
                        return;
                    }
                }
                catch
                {
                    //从集合中移除客户端套接字
                    dictSocket.Remove(socketClient.RemoteEndPoint.ToString());
                    //从集合中移除客户端线程
                    dictThread.Remove(socketClient.RemoteEndPoint.ToString());
                    //从列表中移除客户端套接字的远程终结点
                    deleteClientSocket(socketClient.RemoteEndPoint.ToString());
                    //跨线程显示提示数据
                    delegateShowMseeage("异常:" + "客户端" + socketClient.RemoteEndPoint.ToString() + "断开连接");
                    //释放该线程
                    return;
                }
            }
        }


        /// <summary>
        /// 综合处理接受到的数据
        /// </summary>
        /// <param name="datas"></param>
        /// <param name="length"></param>
        void receiveDataIntegratedProcessing(byte[] datas, int length)
        {
            //if (length == 5)
            //{
            //    if (datas[0] == 0x11 && datas[4] == 0x11)
            //    {
            //        foreach (var clients in dictSocket)
            //        {
            //            newOneThreadSendDataToClient(clients.Value, datas, length);
            //        }
            //    }
            //    else if (datas[0] == 0x12 && datas[4] == 0x12)
            //    {
            //        foreach (var clients in dictSocket)
            //        {
            //            newOneThreadSendDataToClient(clients.Value, datas, length);
            //        }
            //    }
            //}


            //*******************************************************************
            //将接受的数据发送给所有客户端
            //*******************************************************************
            //遍历客户端套接字的集合
            foreach (var clients in dictSocket)
            {
                //新建一条线程发送数据到客户端
                newOneThreadSendDataToClient(clients.Value, datas, length);
            }
        }


        void newOneThreadSendDataToClient(Socket clientSocket, byte[] datas, int length)
        {
            //跨线程显示提示消息
            delegateShowMseeage("新建一条线程准备开始发送数据");
            //新建发送数据的参数模型
            dataSendArgsMode sendDataArgs = new dataSendArgsMode();
            //将客户端套接字绑定到模型
            sendDataArgs.sockets = clientSocket;
            //将数据绑定到模型
            sendDataArgs.datas = datas;
            //将数据长度绑定到模型
            sendDataArgs.length = length;
            //新建发送数据到客户端的线程
            Thread threadSendDataToClient = new Thread(sendDataToClient);
            //后台运行线程
            threadSendDataToClient.IsBackground = true;
            //启动线程,并将 发送数据的参数模型 绑定到线程执行的方法
            threadSendDataToClient.Start(sendDataArgs);
        }


        /// <summary>
        /// 发送数据到客户端
        /// </summary>
        /// <param name="obj"></param>
        void sendDataToClient(object obj)
        {
            //获取用于发送数据的参数模型
            dataSendArgsMode args = obj as dataSendArgsMode;
            try
            {
                //从数据参数模型中提取数据发送到模型中的客户端
                args.sockets.Send(args.datas, 0, args.length, SocketFlags.None);
                //跨线程显示提示消息
                delegateShowMseeage("数据:" + getStringFormByte(args.datas, args.length) + "发送到了客户端:" + args.sockets.RemoteEndPoint.ToString());
                delegateShowMseeage("数据发送完毕,关闭线程");
                //释放该线程
                return;
            }
            catch
            {
                //从集合中移除客户端套接字
                dictSocket.Remove(args.sockets.RemoteEndPoint.ToString());
                //从集合中移除客户端线程
                dictThread.Remove(args.sockets.RemoteEndPoint.ToString());
                //从列表中移除客户端套接字的远程终结点
                deleteClientSocket(args.sockets.RemoteEndPoint.ToString());
                //跨线程显示提示消息
                delegateShowMseeage("异常:" + "客户端" + args.sockets.RemoteEndPoint.ToString() + "断开连接" + ",关闭该线程");
                //释放该线程
                return;
            }
        }


        /// <summary>
        /// 从列表中删除客户端
        /// </summary>
        /// <param name="socket"></param>
        void deleteClientSocket(string strClientSocket)
        {
            //封装一个方法进行委托
            Action<string> actionDelegate = (x) =>
            {
                //从列表中移除指定客户端套接字的远程终结点
                lbOnlineClient.Items.Remove(x.ToString());
            };
            //将参数委托到指定方法执行
            txtMessage.Invoke(actionDelegate, strClientSocket);
        }


        /// <summary>
        /// 添加客户端到列表
        /// </summary>
        /// <param name="clientSocket"></param>
        void addClientSocket(string strClientSocket)
        {
            //封装一个方法进行委托
            Action<string> actionDelegate = (x) =>
            {
                //向列表中添加指定客户端套接字的远程终结点
                lbOnlineClient.Items.Add(x.ToString());
            };
            //将参数委托到指定方法执行
            txtMessage.Invoke(actionDelegate, strClientSocket);
        }


        /// <summary>
        /// 跨线程显示接受到的数据
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="datas"></param>
        /// <param name="length"></param>
        void delegateShowReceiveData(Socket socket, Byte[] datas, int length)
        {
            //封装一个方法进行委托
            Action<string> actionDelegate = (x) =>
            {
                //向文本框追加文本
                txtMessage.AppendText(System.DateTime.Now.ToString()+ " -> "+ x.ToString() + "\r\n");
                txtMessage.ScrollToCaret();
            };
            //将参数委托到指定方法执行
            txtMessage.Invoke(actionDelegate, "收到来自 " + socket.RemoteEndPoint.ToString() + " 的数据:" + getStringFormByte(datas, length));
        }




        /// <summary>
        /// 跨线程显示数据
        /// </summary>
        /// <param name="message"></param>
        void delegateShowMseeage(string message)
        {
            //封装一个方法进行委托
            Action<string> actionDelegate = (x) =>
            {
                if (txtMessage.Text.Length > 200000)
                    txtMessage.Text = string.Empty;
                //向文本框追加文本
                txtMessage.AppendText(System.DateTime.Now.ToString()+" -> " + x.ToString() + "\r\n");
                txtMessage.ScrollToCaret();
            };
            //将参数委托到指定方法执行
            txtMessage.Invoke(actionDelegate, message);
        }


        /// <summary>
        /// 显示数据
        /// </summary>
        /// <param name="message"></param>
        void showMesssge(string message)
        {
            //向文本框追加文本
            txtMessage.AppendText(System.DateTime.Now.ToString() + " -> " + message + "\r\n");
            txtMessage.ScrollToCaret();
        }




        /// <summary>
        /// 16进制的字符串形式
        /// </summary>
        /// <param name="data"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        string getStringFormByte(byte[] data, int length)
        {
            string str = "";
            for (int i = 0; i < length; i++)
            {
                str += data[i].ToString("X").PadLeft(2, '0') + ' ';
            }
            return str;
        }
    }


    /// <summary>
    /// 发送数据的参数
    /// </summary>
    class dataSendArgsMode
    {
        /// <summary>
        /// 套接字
        /// </summary>
        public Socket sockets;


        /// <summary>
        /// 数据
        /// </summary>
        public byte[] datas;


        /// <summary>
        /// 长度
        /// </summary>
        public int length;
    }
}
原创粉丝点击