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
}
}
心跳连接,接上篇
最新推荐文章于 2024-08-26 13:10:54 发布
![](https://img-home.csdnimg.cn/images/20240711042549.png)