server的代码public abstract class Server {static readonly ILog logger = LogManager.GetLogger(typeof(Server));public int Port { get; set; }public event ClientEventHandler OnClientAcceptEvent;public event ClientEventHandler OnClientOnlineEvent;public event ClientEventHandler OnClientRemoveEvent;private bool bStarted;static private int NextClientId = 0;private TcpListener _listener;protected Dictionary<int, Client> id2client = new Dictionary<int, Client>();private List<Client> noHeartBeatClients = new List<Client>();public bool HasHeartBeat;private int CheckHeartBeatInterval = 30 * 1000;// msprotected System.Timers.Timer CheckHeartBeatTimer = new System.Timers.Timer();private object id2clientCS = new object();private object noHeartBeatClientsCS = new object();private Server() {CheckHeartBeatTimer.Elapsed += (o1, a1) => {if(HasHeartBeat == false) return;List<Client> kickClientList = new List<Client>();lock(id2clientCS) {try {DateTime now = DateTime.Now;foreach(KeyValuePair<int, Client> pair in id2client) {try {Client client = pair.Value;TimeSpan offset = now - client.LastHeartBeat;if(client != null && client.State == Client.ConnectionState.Connected && offset.TotalMilliseconds > CheckHeartBeatInterval) {kickClientList.Add(pair.Value);logger.InfoFormat("检测到心跳超时: [IP]{0}, [ID]{1}, [Time]{2}", client.ClientIpAddress, pair.Key, DateTime.Now.ToString());}} catch { }}} catch(Exception ex) {logger.WarnFormat("心跳检测时发生异常: \n{0}", ex);}}kickClientList.ForEach(p => p.Close());lock(noHeartBeatClientsCS) {kickClientList.ForEach(c => noHeartBeatClients.RemoveAll(p => p.Id == c.Id));}};}public Server(int port): this() {this.Port = port;}public List<Client> Clients {get {List<Client> result = new List<Client>();lock(id2clientCS) {foreach(Client each in id2client.Values) {result.Add(each);}}return result;}}public virtual void Open() {_listener = new TcpListener(Port);logger.InfoFormat("Server#Open port={0}", Port);try {_listener.Start();if(HasHeartBeat) {CheckHeartBeatTimer.Stop();CheckHeartBeatTimer.Interval = CheckHeartBeatInterval;CheckHeartBeatTimer.Start();}_listener.BeginAcceptTcpClient(new AsyncCallback(OnAccept), null);bStarted = true;} catch(SocketException ex) {logger.WarnFormat("服务器监听发生异常:{0}\nSocket ErrorCode: {1}\n提示:请检查端口是否已被占用", ex.Message, ex.ErrorCode);throw ex;} catch(Exception ex) {logger.Warn(ex);throw ex;}}public virtual void Close() {try {if(HasHeartBeat) {CheckHeartBeatTimer.Stop();}_listener.Stop();bStarted = false;lock(id2clientCS) {foreach(Client each in id2client.Values) {try { if(each != null)each.Close(); } catch { }}id2client.Clear();}} catch(Exception ex) {logger.Warn(ex);throw ex;}}private void OnAccept(IAsyncResult ar) {try {Client client = CreateClient(NextClientId++, _listener.EndAcceptTcpClient(ar), this);client.LastHeartBeat = DateTime.Now;client.PostOfflineEvent += (obj, args) => RemoveClient(client);lock(id2clientCS) {id2client.Add(client.Id, client);}lock(noHeartBeatClientsCS) {noHeartBeatClients.Add(client);}if(OnClientAcceptEvent != null) OnClientAcceptEvent(client);} catch(ObjectDisposedException) { } catch(Exception ex) {logger.Warn(ex);} finally {try {_listener.BeginAcceptTcpClient(new AsyncCallback(OnAccept), null);} catch(Exception) {// ignore}}}protected abstract Client CreateClient(int id, TcpClient tcpClient, Server server);public void RemoveClient(Client client) {if(bStarted == false) return;lock(id2clientCS) {id2client.Remove(client.Id);}if(OnClientRemoveEvent != null) OnClientRemoveEvent(client);}public void GetHeartBeat(Client client) {if(HasHeartBeat == false) return;client.LastHeartBeat = DateTime.Now;lock(noHeartBeatClientsCS) {int index = noHeartBeatClients.FindIndex(p => p.Id == client.Id);if(index == -1) return;try {if(OnClientOnlineEvent != null) OnClientOnlineEvent(client);} catch(Exception ex) {logger.Warn(ex);}noHeartBeatClients.RemoveAt(index);}}
}

-----解决方案--------------------------------------------------------
在定时器里隔段时间就发送几个字节的数据。如果3次没有返回则断开 
------解决方案--------------------------------------------------------
客户端:
30秒发送一个心跳包到服务器

服务器:
接收到心跳包,更新LastHeartbeatTime
并且有一个线程,一分钟扫描一次,如果LastHeartbeatTime超过一分钟没更新的视为下线

------解决方案--------------------------------------------------------

模拟心跳的机制
使用直接调用函数模拟心跳,没有涉及到socket
写得不好,不要太挑剔
using System;
using System.Collections.Generic;
using System.Threading;namespace ConsoleApplication1
{// 客户端离线委托public delegate void ClientOfflineHandler(ClientInfo client);// 客户端上线委托public delegate void ClientOnlineHandler(ClientInfo client);public class Program{/// <summary>/// 客户端离线提示/// </summary>/// <param name="clientInfo"></param>private static void ClientOffline(ClientInfo clientInfo){Console.WriteLine(String.Format("客户端{0}离线,离线时间:\t{1}", clientInfo.ClientID, clientInfo.LastHeartbeatTime));}/// <summary>/// 客户端上线提示/// </summary>/// <param name="clientInfo"></param>private static void ClientOnline(ClientInfo clientInfo){Console.WriteLine(String.Format("客户端{0}上线,上线时间:\t{1}", clientInfo.ClientID, clientInfo.LastHeartbeatTime));}static void Main(){// 服务端Server server = new Server();// 服务端离线事件server.OnClientOffline += ClientOffline;// 服务器上线事件server.OnClientOnline += ClientOnline;// 开启服务器server.Start();// 模拟100个客户端Dictionary<Int32, Client> dicClient = new Dictionary<Int32, Client>();for (Int32 i = 0; i < 100; i++){// 这里传入server只是为了方便而已Client client = new Client(i + 1, server);dicClient.Add(i + 1, client);// 开启客户端client.Start();}System.Threading.Thread.Sleep(1000);while (true){Console.WriteLine("请输入要离线的ClientID,输入0则退出程序:");String clientID = Console.ReadLine();if (!String.IsNullOrEmpty(clientID)){Int32 iClientID = 0;Int32.TryParse(clientID, out iClientID);if (iClientID > 0){Client client;if (dicClient.TryGetValue(iClientID, out client)){// 客户端离线client.Offline = true;}}else{return;}}}}}/// <summary>/// 服务端/// </summary>public class Server{public event ClientOfflineHandler OnClientOffline;public event ClientOnlineHandler OnClientOnline;private Dictionary<Int32, ClientInfo> _DicClient;/// <summary>/// 构造函数/// </summary>public Server(){_DicClient = new Dictionary<Int32, ClientInfo>(100);            }/// <summary>/// 开启服务端/// </summary>public void Start(){// 开启扫描离线线程Thread t = new Thread(new ThreadStart(ScanOffline));t.IsBackground = true;t.Start();}/// <summary>/// 扫描离线/// </summary>private void ScanOffline(){while (true){// 一秒扫描一次System.Threading.Thread.Sleep(1000);lock (_DicClient){foreach (Int32 clientID in _DicClient.Keys){ClientInfo clientInfo = _DicClient[clientID];// 如果已经离线则不用管if (!clientInfo.State){continue;}// 判断最后心跳时间是否大于3秒TimeSpan sp = System.DateTime.Now - clientInfo.LastHeartbeatTime;if (sp.Seconds >= 3){// 离线,触发离线事件if (OnClientOffline != null){OnClientOffline(clientInfo);}// 修改状态clientInfo.State = false;}}}}}/// <summary>/// 接收心跳包/// </summary>/// <param name="clientID">客户端ID</param>public void ReceiveHeartbeat(Int32 clientID){lock (_DicClient){ClientInfo clientInfo;if (_DicClient.TryGetValue(clientID, out clientInfo)){// 如果客户端已经上线,则更新最后心跳时间clientInfo.LastHeartbeatTime = System.DateTime.Now;}else{// 客户端不存在,则认为是新上线的clientInfo = new ClientInfo();clientInfo.ClientID = clientID;clientInfo.LastHeartbeatTime = System.DateTime.Now;clientInfo.State = true;_DicClient.Add(clientID, clientInfo);// 触发上线事件if (OnClientOnline != null){OnClientOnline(clientInfo);}}}}}/// <summary>/// 客户端/// </summary>public class Client{public Server Server;public Int32 ClientID;public Boolean Offline;/// <summary>/// 构造函数/// </summary>/// <param name="clientID"></param>/// <param name="server"></param>public Client(Int32 clientID, Server server){ClientID = clientID;Server = server;Offline = false;}/// <summary>/// 开启客户端/// </summary>public void Start(){// 开启心跳线程Thread t = new Thread(new ThreadStart(Heartbeat));t.IsBackground = true;t.Start();}/// <summary>/// 向服务器发送心跳包/// </summary>private void Heartbeat(){while (!Offline){// 向服务端发送心跳包Server.ReceiveHeartbeat(ClientID);System.Threading.Thread.Sleep(1000);}}}/// <summary>/// 客户端信息/// </summary>public class ClientInfo{// 客户端IDpublic Int32 ClientID;// 最后心跳时间public DateTime LastHeartbeatTime;// 状态public Boolean State;}
}

转载于:https://www.cnblogs.com/fx2008/p/4223392.html

socket 怎么设置心跳判断连接相关推荐

  1. socket通信时如何判断当前连接是否断开--select函数,心跳线程,QsocketNotifier监控socket...

    client与server建立socket连接之后,如果突然关闭server,此时,如果不在客户端close(socket_fd),会有不好的影响: QsocketNotifier监控socket的槽 ...

  2. 【转】C# 网络连接中异常断线的处理:ReceiveTimeout, SendTimeout 及 KeepAliveValues(设置心跳)

    在使用 TcpClient 网络连接中常常会发生客户端连接异常断开, 服务端需要设置检测手段进行这种异常的处理: 1.对于短连接, 通过对 Socket 属性ReceiveTimeout 和 Send ...

  3. JAVA 判断Socket 远程端是否断开连接

    JAVA 判断Socket 远程端是否断开连接 最近在做项目的时候,遇到这样一个问题,如何判断 Socket 远程端连接是否关闭,如果关闭的话,就要重建连接Socket的类提供了一些已经封装好的方法, ...

  4. 远程主机关闭了一个现有连接python_python 远程主机强迫关闭了一个现有的连接 socket 超时设置 errno 10054 | 学步园...

    python socket.error: [Errno 10054] 远程主机强迫关闭了一个现有的连接.问题解决方案: 前几天使用python读取网页.因为对一个网站大量的使用urlopen操作,所以 ...

  5. python远程主机强迫关闭了_[转] python 远程主机强迫关闭了一个现有的连接 socket 超时设置 errno 10054...

    python socket.error: [Errno 10054] 远程主机强迫关闭了一个现有的连接.问题解决方案: 前几天使用python读取网页.因为对一个网站大量的使用urlopen操作,所以 ...

  6. Socket.Connected 不能作为TCP连接的判断依据

    TCP正常通信时Socket.Connected的值为false. 参考微软的帮助说明: http://technet.microsoft.com/zh-cn/magazine/system.net. ...

  7. linux socket recv函数如何判断收完一包_linux服务器端编程之高性能服务器架构设计总结...

    所谓高性能就是服务器能流畅地处理各个客户端的连接并尽量低延迟地应答客户端的请求:所谓高并发,指的是服务器可以同时支持多的客户端连接,且这些客户端在连接期间内会不断与服务器有数据来往. 这篇文章将从两个 ...

  8. Android Socket通讯 之 心跳消息

    心跳消息 前言 正文 一.状态判断 二.心跳消息发送 三.心跳消息回复 四.源码 前言   不知道大家国庆节过的咋样,有没有学习呢?我是闲着没事就写点东西,本文篇幅较短,只是实现了心跳消息的处理,下面 ...

  9. Java:socket服务端,socket服务端支持多连接,socket客户端,socket客户端支持发送和接受

    一.Java之socket服务端 新建一个Java工程 命名 给他先创建一个类 在类里面我们做一个main 这里面也需要,创建套接字,IP号,端口号 但是java中有一个类         Serve ...

  10. linux tcp连接计算机,计算机基础知识——linux socket套接字tcp连接分析

    2016.7.4 今天晚上对项目顶层文件(daemon)进行了分析,对其中的TCP连接进行具体的代码级分析. 1.需求分析 首先得知道我们这里为什么要用TCP连接,我们的整个测试系统是由上位机作为客户 ...

最新文章

  1. 周永亮 《我是职业人》
  2. android studio 3.0新功能介绍
  3. VTK:Utilities之FunctionParser
  4. Node.js + Express + handlebars搭建个人网站(1)
  5. UML 数据建模EA的基本使用——《用例图的使用》
  6. .NET Framework 4.7发布,支持Windows 10创作者更新
  7. 使用NoSQLUnit测试Spring Data MongoDB应用程序
  8. 重学TCP协议(10)SYN flood 攻击
  9. 蛮力法在求解最优解问题中的应用(JAVA)--旅行家问题、背包问题、分配问题
  10. td中bug处理过程_特斯拉的致命BUG,埃安LX的L3能解开吗?
  11. 如何在矩池云上查看cudnn版本
  12. 用JavaScript获取输入的特殊字符
  13. 【大数据实验2】hadoop配置、测试和实例
  14. 复制粘贴之后出现问号怎么办_复制粘贴文字变乱码解决
  15. 家用中央空调设计浅议
  16. 经验谈:调查问卷问题设计“六忌”
  17. 用PHPnow运行PHP项目以及PHPnow相关问题的解决
  18. 第二周 Linux文件管理类命令及bash基本特性
  19. 新浪微博热搜榜“背后的男人”讲述热搜背后的秘密
  20. BZOJ 1413: [ZJOI2009]取石子游戏 博弈+Dp

热门文章

  1. js圆角矩形旋转(div拼凑)
  2. pm2启动jenkins不存在tty的问题
  3. c#中,如何获取日期型字段里的年、月、日?
  4. Java求解迷宫问题:栈与回溯算法
  5. windows中squid更改默认安装路径配置说明
  6. 代码从stepping stone搬移到内存
  7. HDU1712:ACboy needs your help(分组背包)
  8. 数据库基础知识——互动百科
  9. Adversarial learned Inference(对抗学习推断器)
  10. nginx.conf 配置详解