TCPServer.cs 12.3 KB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Dolen.Communication.TCP
{
    public class TCPServer
    {
        Thread threadWatch = null; // 负责监听客户端连接请求的线程;
        Socket socketWatch = null;
        int buffLength = 1024;// 定义一个1M的缓存区;
        List<Client> Clients = new List<Client>();
        //Dictionary<string, Socket> dict = new Dictionary<string, Socket>();
        //Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();
        log4net.ILog Log;
        private bool loop = false;
        /// <summary>
        /// 消息变化委托
        /// </summary>
        /// <param name="clientKey">客户端信息</param>
        /// <param name="msg">客户端发送的消息</param>
        public delegate void MsgEventHandler(string clientKey, string msg);
        public delegate void ClientChangedEventHandler(List<Client> clients);
        public delegate void ServerStateChangedEventHandler(bool state);
        /// <summary>
        /// 消息接收事件 (string clientKey, string msg)
        /// </summary>
        public event MsgEventHandler RecvMsgEvent;
        /// <summary>
        /// 客户端变化事件 (List<string> clientKey)
        /// </summary>
        public event ClientChangedEventHandler ClientChangedEvent;

        public event ServerStateChangedEventHandler ServerStateChangedEvent;
        /// <summary>
        /// 是否打开调试
        /// </summary>
        public bool IsDebug { get; set; } = false;
        /// <summary>
        /// 服务端IP
        /// </summary>
        public string IP { get; private set; }
        /// <summary>
        /// 服务端信息
        /// </summary>
        public string ServerInfo
        {
            get
            {
                return string.Format("{0}:{1}", IP, Port.ToString());
            }
        }
        /// <summary>
        /// 服务端端口
        /// </summary>
        public int Port { get; private set; }
        /// <summary>
        /// 启动状态
        /// </summary>
        public bool Started { get; private set; }
        public TCPServer(string ip = "0.0.0.0", int port = 8888, string logName = "TCPServer")
        {
            Log = log4net.LogManager.GetLogger(logName);
            IP = ip;
            Port = port;
            // 创建负责监听的套接字,注意其中的参数;
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            // 获得文本框中的IP对象;
            IPAddress address = IPAddress.Parse(IP);
            // 创建包含ip和端口号的网络节点对象;
            IPEndPoint endPoint = new IPEndPoint(address, Port);
            try
            {
                // 将负责监听的套接字绑定到唯一的ip和端口上;
                socketWatch.Bind(endPoint);
            }
            catch (SocketException se)
            {
                Log.Error(string.Format("套接字绑定到服务端[{0}]出现异常", ServerInfo), se);
                return;
            }
            // 设置监听队列的长度;
            socketWatch.Listen(10);
            // 创建负责监听的线程;
            threadWatch = new Thread(WatchConnecting);
            threadWatch.IsBackground = true;
            threadWatch.Start();
        }
        ~TCPServer()
        {
            try
            {
                socketWatch.Dispose();
            }
            catch { }
        }
        /// <summary>
        /// 设置缓存区长度
        /// </summary>
        public void SetBuffLength(int len)
        {
            buffLength = len;
        }
        /// <summary>
        /// 开启服务
        /// </summary>
        public void Start()
        {
            if (Started)
                return;
            loop = true;
            Started = true;
            Log.Info(string.Format("TCP服务端[{0}]开启监听成功!", ServerInfo));
            ServerStateChangedEvent?.Invoke(Started);
        }
        public void Stop()
        {
            loop = false;
            //foreach (string t in dictThread.Keys)
            //{
            //    try
            //    {
            //        dictThread[t].Abort();
            //    }
            //    catch (Exception ex)
            //    {
            //        Log.Error(string.Format("关闭连接客户端[{0}]的线程失败", t), ex);
            //    }
            //}
            foreach (Client client in Clients)
            {
                try
                {
                    client.RecvMsgThread.Abort();
                }
                catch (Exception ex)
                {
                    Log.Error(string.Format("关闭连接客户端[{0}]的线程失败", client.EndPoint), ex);
                }
                try
                {
                    client.Socket.Close();
                }
                catch (Exception ex)
                {
                    Log.Error(string.Format("关闭连接客户端[{0}]Socket失败", client.EndPoint), ex);
                }
            }
            if (Clients.Count > 0) Clients.Clear();

            //foreach (string socket in dict.Keys)
            //{
            //    try
            //    {
            //        dict[socket].Close();
            //    }
            //    catch (Exception ex)
            //    {
            //        Log.Error(string.Format("关闭连接客户端[{0}]Socket失败", socket), ex);
            //    }
            //}
            Started = false;
            ServerStateChangedEvent?.Invoke(Started);
            ClientChangedEvent?.Invoke(Clients);
            Log.Info(string.Format("TCP服务端[{0}]关闭监听成功!", ServerInfo));
        }
        /// <summary>
        /// 监听客户端请求的方法;
        /// </summary>
        void WatchConnecting()
        {
            while (true)  // 持续不断的监听客户端的连接请求;
            {
                while (loop)
                {
                    // 开始监听客户端连接请求,Accept方法会阻断当前的线程;
                    Socket sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;

                    Client client = new Client();
                    client.EndPoint = sokConnection.RemoteEndPoint.ToString();
                    client.Socket = sokConnection;
                    if (CheckExistClient(sokConnection.RemoteEndPoint.ToString()))
                    {
                        Client remove = Clients.Find(s => s.IP.Equals(client.IP));
                        try
                        {
                            remove.RecvMsgThread.Abort();
                            remove.Socket.Close();
                        }
                        catch (Exception ex)
                        {
                            Log.Error("WatchConnecting", ex);
                        }

                        Clients.Remove(remove);
                    }
                    Log.Info(string.Format("客户端[{0}]连接服务端[{1}]成功", sokConnection.RemoteEndPoint.ToString(), ServerInfo));
                    Thread thr = new Thread(RecMsg);
                    thr.IsBackground = true;
                    thr.Start(sokConnection);
                    client.RecvMsgThread = thr;
                    Clients.Add(client);
                    ClientChangedEvent?.Invoke(Clients);
                }
                Thread.Sleep(5);
            }
        }
        void RecMsg(object sokConnectionparn)
        {
            Socket sokClient = sokConnectionparn as Socket;
            while (loop)
            {
                // 定义一个缓存区;
                byte[] arrMsgRec = new byte[buffLength];
                // 将接收到的数据存入到输入  arrMsgRec中;
                int length = -1;
                if (sokClient.Poll(-1, SelectMode.SelectRead))
                {
                    try
                    {
                        length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
                        if (length == 0)//连接正常断开
                        {
                            Log.Info(string.Format("客户端[{0}]断开与服务端[{1}]的连接", sokClient.RemoteEndPoint.ToString(), ServerInfo));
                            // 从 通信套接字 集合中删除被中断连接的通信套接字;
                            RemoveClient(sokClient.RemoteEndPoint.ToString());
                            ClientChangedEvent?.Invoke(Clients);
                            break;
                        }
                    }
                    catch (SocketException se)
                    {
                        Log.Error(string.Format("客户端[{0}]接收服务端[{1}]的消息出现异常", sokClient.RemoteEndPoint.ToString(), ServerInfo), se);
                        // 从 通信套接字 集合中删除被中断连接的通信套接字;
                        RemoveClient(sokClient.RemoteEndPoint.ToString());
                        break;
                    }
                    catch (Exception e)
                    {
                        Log.Error(string.Format("客户端[{0}]接收服务端[{1}]的消息出现异常", sokClient.RemoteEndPoint.ToString(), ServerInfo), e);
                        RemoveClient(sokClient.RemoteEndPoint.ToString());
                        ClientChangedEvent?.Invoke(Clients);
                        break;
                    }
                }

                if (length > 0)
                {
                    string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, length);// 将接收到的字节数据转化成字符串;
                                                                                              //if (IsDebug)
                    Log.Info($"服务端[{ServerInfo}]收到客户端[{sokClient.RemoteEndPoint.ToString()}]的消息:{strMsg}");
                    //Log.Info(string.Format("服务端[{0}]收到客户端[{1}]的消息:{2}[{3} Bytes]", ServerInfo, sokClient.RemoteEndPoint.ToString(), strMsg,length));
                    RecvMsgEvent?.Invoke(sokClient.RemoteEndPoint.ToString(), strMsg);
                }
                Thread.Sleep(1);
            }
        }

        /// <summary>
        /// 向客户端发送信息
        /// </summary>
        public void SendMsg(string clientKey, string txt)
        {
            try
            {
                byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(txt); // 将要发送的字符串转换成Utf-8字节数组;
                                                                         // arrSendMsg[0] = 0; // 表示发送的是消息数据
                                                                         //Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);        
                int len = GetClient(clientKey).Socket.Send(arrMsg);
                Log.Info($"服务端[{ServerInfo}]向客户端[{clientKey}]发送消息:{txt}");
            }
            catch (Exception e)
            {
                Log.Error(string.Format("服务端[{0}]向客户端[{1}]发送消息异常:{2}", ServerInfo, clientKey, txt), e);
                RemoveClient(clientKey);
                ClientChangedEvent?.Invoke(Clients);
            }

        }
        bool CheckExistClient(string endpoint)
        {
            string ip = endpoint.Split(':')[0];
            Client client = Clients.Find(s => s.IP.Equals(ip));
            return client != null;
        }
        void RemoveClient(string endpoint)
        {
            Client client = Clients.Find(s => s.EndPoint.Equals(endpoint));
            Clients.Remove(client);
        }
        Client GetClient(string endpoint)
        {
            return Clients.Find(s => s.EndPoint.Equals(endpoint));
        }
    }
    public class Client
    {
        /// <summary>
        /// 终端信息
        /// </summary>
        public string EndPoint { get; set; }
        public string IP { get { return EndPoint.Split(':')[0]; } }
        /// <summary>
        /// 套接字
        /// </summary>
        public Socket Socket { get; set; }
        /// <summary>
        /// 接收的消息的线程
        /// </summary>
        public Thread RecvMsgThread { get; set; }
    }

}