心跳连接,接上篇

这个代码示例展示了如何使用C#实现TCP服务器的心跳检测功能,包括客户端上线、下线事件处理,以及心跳超时后判断客户端是否离线。同时,客户端也实现了向服务器发送心跳包并检测服务器响应的功能,当心跳中断时,客户端会触发离线事件。
摘要由CSDN通过智能技术生成
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;
using System.Windows.Forms;

namespace HServer
{
    static class HEARTTOOL
    {
        #region Server心跳

        /// <summary>
        /// 服务端
        /// </summary>
        public static class heartBeatServer
        {// 客户端离线委托
            public delegate void ClientOfflineHandler(ClientInfo cl);
            // 客户端上线委托
            public delegate void ClientOnlineHandler(ClientInfo cl);
            public static event ClientOfflineHandler OnClientOffline;
            public static event ClientOnlineHandler OnClientOnline;
            public static int heartPort;
            private static TcpListener Lis;
            public static int timeout;//超时时间
            //DIC:id,clientinfo
            public static Dictionary<EndPoint, ClientInfo> _DicClient = new Dictionary<EndPoint, ClientInfo>();

            /// <summary>
            /// 开启服务端
            /// </summary>
            public static void Start()
            {

                // 开启扫描离线线程
                Thread t2 = new Thread(new ThreadStart(ListenClientBeat));
                t2.IsBackground = true;
                t2.Start();
                Thread t1 = new Thread(new ThreadStart(ScanOffline));
                t1.IsBackground = true;
                t1.Start();
                
            }

            /// <summary>
            /// 扫描离线
            /// </summary>
            private static void ScanOffline()
            {
                while (true)
                {
                    // 一秒扫描一次
                    System.Threading.Thread.Sleep(1000);

                    lock (_DicClient)
                    {
                        foreach (EndPoint eps in _DicClient.Keys)
                        {
                            // 判断最后心跳时间是否大于3秒
                            TimeSpan sp = System.DateTime.Now - _DicClient[eps].LastHeartbeatTime;
                            Console.WriteLine(sp.Seconds + "");//停顿一下连续发好几个ID
                            if (sp.Seconds >= 5)
                            {
                                // 离线,触发离线事件
                                if (OnClientOffline != null)
                                {
                                    OnClientOffline(_DicClient[eps]);
                                    Console.WriteLine( "客户端下线");
                                }
                                // 修改状态
                                _DicClient[eps].offline = true;
                            }
                        }
                    }
                }
            }

            /// <summary>
            /// 接收心跳包
            /// </summary>
            /// <param name="clientID">客户端ID</param>
            public static void ListenClientBeat()
            {
                try
                {
                    IPEndPoint IPP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), heartPort);
                    Lis = new TcpListener(IPP);
                    Lis.Start();
                    while (true)
                    {
                        Socket tempSocket = Lis.AcceptSocket();//建立新连接,阻塞方法
                        EndPoint ep = tempSocket.RemoteEndPoint;
                        //MessageBox.Show("438");
                        if (_DicClient.ContainsKey(ep))
                        {
                            //重复上线?
                            MessageBox.Show("重复上线:" + ep);
                        }
                        else
                        {
                            //建一个死循环线程用于收发数据
                            Thread t3 = new Thread(sr);
                            t3.Start(tempSocket);

                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e + "");
                }
            }
            /// <summary>
            /// 收发数据
            /// </summary>
            /// <param name="socket"></param>
            public static void sr(object socket)
            {
                Socket tempsocket = (Socket)socket;
                EndPoint ee = tempsocket.RemoteEndPoint;
                bool alreadyConnected = false;//是否已经存入字典
                while (true)
                {
                    try
                    {
                        using (NetworkStream ns = new NetworkStream(tempsocket))
                        {
                            byte[] bb = new byte[1024];
                            //得到ID

                            int Res_Len = ns.Read(bb, 0, bb.Length);//阻塞?
                            String clientid = Encoding.Default.GetString(bb, 0, Res_Len);
                            Console.WriteLine("读到客户端传来的ID:"+clientid);
                            if (clientid.Length!=4)
                            Console.WriteLine(clientid);
                            if (Res_Len > 0)
                            {
                                ns.Write(Encoding.Default.GetBytes(clientid), 0, Encoding.Default.GetBytes(clientid).Length);
                                ns.Flush();
                            }
                            lock (_DicClient)
                            {
                                foreach (EndPoint pe in _DicClient.Keys)
                                {
                                    if (_DicClient[pe].clientid.Equals(clientid))
                                    {//说明早就建立连接,当下只是进行心跳接收与回应
                                        if (_DicClient[pe].offline)
                                        {
                                            //终止当前线程
                                            Console.WriteLine("试图终止当前线程");
                                            _DicClient.Remove(pe);
                                            Thread.CurrentThread.Abort();
                                            Console.WriteLine("终止当前线程");
                                        }
                                        else {
                                            _DicClient[pe].LastHeartbeatTime = DateTime.Now;
                                            alreadyConnected = true;
                                        }                                                                               
                                    }
                                }
                                if (!alreadyConnected)
                                {
                                    ClientInfo cI = new ClientInfo();
                                    cI.clientid = clientid;
                                    cI.socket = tempsocket;
                                    cI.offline = false;
                                    cI.LastHeartbeatTime = DateTime.Now;
                                    _DicClient.Add(ee, cI);
                                    OnClientOnline(cI);
                                    alreadyConnected = true;
                                }
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        //Thread.CurrentThread.Abort();
                        Console.WriteLine(tempsocket.Connected+"终止当前线程失败:" + e);
                    }
                }
            }
            /// <summary>
            /// 客户端信息
            /// </summary>
            public class ClientInfo
            {
                //客户端编号
                public string clientid;
                // 套接字
                public Socket socket;
                // 最后心跳时间
                public DateTime LastHeartbeatTime;
                //离线状态,真表示离线
                public bool offline;
            }
        }

        #endregion

        #region Client心跳
        /// <summary>
        /// 客户端
        /// </summary>
        public static class heartBeatClient
        {
            // 客户端离线委托
            public delegate void ServerOfflineHandler();
            // 客户端上线委托
            public delegate void ServerOnlineHandler();
            public static string ip;//初始化
            public static Int16 port;//初始化
            public static string ClientID;//初始化
            public static Int16 tryTimes;//初始化,重发多少次没反应算断线
            private static TcpClient heartClient;
            private static Socket socketClient;
            private static DateTime lastBeatTime;
            private static Int16 count;
            public static event ServerOfflineHandler OnServerOffline;
            public static event ServerOnlineHandler OnServerOnline;
            private static bool heartAlive = true;//是否继续循环向服务端发送
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="clientID"></param>
            /// <param name="server"></param>
            //public Client(string clientID,string IP,Int16 PORT)
            //{
            //    ClientID = clientID;
            //    ip = IP;
            //    port = PORT;
            //}

            /// <summary>
            /// 开启客户端
            /// </summary>
            public static void Start()
            {
                // 开启心跳线程
                Thread t1 = new Thread(new ThreadStart(Heartbeat));
                t1.IsBackground = true;
                t1.Start(); System.Threading.Thread.Sleep(999);
                Thread t2 = new Thread(new ThreadStart(heartRecieve));
                t2.IsBackground = true;
                t2.Start();
            }

            /// <summary>
            /// 向服务器发送心跳包
            /// </summary>
            private static void Heartbeat()
            {
                heartClient = new TcpClient();
                try
                {
                    heartClient.Connect(ip, port);
                    if (heartClient.Connected)
                    {
                        if (OnServerOnline != null)
                        {
                            OnServerOnline();
                        }
                        socketClient = heartClient.Client;
                        while (heartAlive)
                        {
                            System.Threading.Thread.Sleep(1000);
                            using (NetworkStream heartStream = new NetworkStream(socketClient))
                            {
                                heartStream.Write(Encoding.Default.GetBytes(ClientID), 0, Encoding.Default.GetBytes(ClientID).Length);
                                heartStream.Flush();
                            }

                            count++;
                            if (count >= tryTimes)
                            {
                                TimeSpan sp = System.DateTime.Now - lastBeatTime;
                                if (sp.Seconds >= count)
                                {
                                    heartAlive = false;
                                    socketClient.Close();
                                    heartClient.Close();
                                    // 离线,触发离线事件
                                    if (OnServerOffline != null)
                                    {
                                        OnServerOffline();
                                    }
                                    count = 0;
                                    Thread.CurrentThread.Abort();
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("心跳包发送错误!" + e);
                }
            }
            /// <summary>
            /// 接收服务器返回包
            /// </summary>
            private static void heartRecieve()
            {
                while (true)
                {
                    byte[] bb = new byte[1024];
                    try
                    {
                        using (NetworkStream ns = new NetworkStream(socketClient))
                        {
                            int Res_Len = ns.Read(bb, 0, bb.Length);
                            //得到被控端发送回来的消息,并且分离成数组结构体
                            String serverBack = Encoding.Default.GetString(bb, 0, Res_Len).Trim();
                            if (serverBack.Equals(ClientID))
                            {
                                lastBeatTime = System.DateTime.Now;

                            }

                        }


                    }
                    catch (Exception e) { Console.WriteLine("心跳包接收错误!" + e); }

                }
            }
        }
        #endregion
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值