socket长连接,心跳包怎么实现啊

huhailong520 2016-06-22 09:34:15
最近在做软件和硬件的开发 要用到socket和硬件去联系,我这边是服务端,是socket长连接形式,可以打开多个客服端和我这边服务端通信,正常通信 接受和发送都实现了 没问题,现在就是 客服端会每隔30秒给我发一个心跳包过来检测是否与服务端还是正常连接,所以每个客服端发过来的心跳包我不想去数据库建立一个表去存它的心跳数据 那样数据太多了。在代码里面怎么实现啊,现在就卡这里了,请各位大神帮帮忙啊。下面是我的所有代码!

{
public Service1()
{
InitializeComponent();
}
System.Timers.Timer timer;
private StreamWriter streamWriter; //写文件
Thread threadWatch = null; // 负责监听客户端连接请求的 线程;
Socket socketWatch = null;
private string host = ConfigurationManager.AppSettings["ip"].ToString();
private int port = int.Parse(ConfigurationManager.AppSettings["port"].ToString());
private int second = int.Parse(ConfigurationManager.AppSettings["second"].ToString());
DBAll db = new DBAll();
protected override void OnStart(string[] args)
{
btnBeginListen();

timer = new System.Timers.Timer();
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Interval = second * 1000;
timer.Enabled = true;
timer.Start();
}

protected override void OnStop()
{
WriteError("服务已经停止了!");
}
//socket开启
public void btnBeginListen()
{
// 创建负责监听的套接字
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress address = IPAddress.Parse(host);
// 创建包含ip和端口号的网络节点对象;
IPEndPoint endPoint = new IPEndPoint(address, port);
try
{
// 将负责监听的套接字绑定到唯一的ip和端口上;
socketWatch.Bind(endPoint);
}
catch
{
return;
}
// 设置监听队列的长度;
socketWatch.Listen(100);
// 创建负责监听的线程;
threadWatch = new Thread(WatchConnecting);
threadWatch.IsBackground = true;
threadWatch.Start();

//}
}

/// <summary>
/// 监听客户端请求的方法;
/// </summary>
void WatchConnecting()
{
while (true) // 持续不断的监听客户端的连接请求;
{
// 开始监听客户端连接请求,Accept方法会阻断当前的线程;
Socket sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;
// 客户端的IP信息;
// WriteError(sokConnection.RemoteEndPoint.ToString());
Thread thr = new Thread(RecMsg);
thr.IsBackground = true;
thr.Start(sokConnection);
}
}
/// <summary>
/// 接受信息的方法
/// </summary>
/// <param name="sokConnectionparn"></param>
void RecMsg(object sokConnectionparn)
{
Socket sokClient = sokConnectionparn as Socket;
//List<byte> byteList = new List<byte>();
//int length = -1;
//do
//{
// // 定义一个1M的缓存区;
// byte[] arrMsgRec = new byte[1024];
// // 将接受到的数据存入到输入 arrMsgRec中;
// try
// {
// length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
// byteList.AddRange(arrMsgRec);
// if (length < byteList.ToArray().Length)
// {
// string strMsg = System.Text.Encoding.Default.GetString(byteList.ToArray(), 0, length);// 将接受到的字节数据转化成字符串;
// handleData(strMsg, sokClient);
// }

// }
// catch
// {
// break;
// }

//} while (true);
do
{
byte[] arrMsgRec = new byte[1024];
try
{
int length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
string strMsg = System.Text.Encoding.Default.GetString(arrMsgRec, 0, length);// 将接受到的字节数据转化成字符串;
handleData(strMsg, sokClient);
}
catch
{
break;
}
} while (true);
}

/// <summary>
/// 处理数据的方法
/// </summary>
public void handleData(string str, Socket sokClient)
{

string[] strAll = str.Split(' ');
switch (int.Parse(strAll[8]))
{
case 2://登陆

break;
case 1://心跳
heartbeat(str, sokClient);
break;

}


}


#region 心跳
public void heartbeat(string str, Socket sokClient)
{

}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{

}
#endregion

public void WriteError(string message)
{
try
{
string directPath = System.AppDomain.CurrentDomain.BaseDirectory + "info\\";
if (!Directory.Exists(directPath)) //判断文件夹是否存在,如果不存在则创建
{
Directory.CreateDirectory(directPath);
}
directPath += string.Format(@"\{0}.log", DateTime.Now.ToString("yyyy-MM-dd"));
if (streamWriter == null)
{
streamWriter = !File.Exists(directPath) ? File.CreateText(directPath) : File.AppendText(directPath); //判断文件是否存在如果不存在则创建,如果存在则添加。
}
streamWriter.WriteLine("***********************************************************************");
streamWriter.WriteLine("错误时间:" + DateTime.Now.ToString("HH:mm:ss"));
if (message != null)
{
streamWriter.WriteLine("异常信息:\r\n" + message);
}
}
finally
{
if (streamWriter != null)
{
streamWriter.Flush();
streamWriter.Dispose();
streamWriter = null;
}
}
}
}

主要是心跳包的检测是检测哪个方法 或者放在哪个位置啊?
...全文
1490 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_40686805 2018-10-16
  • 打赏
  • 举报
回复
大神,能不能发个源码过来,最近在写这方面,一直搞不定心跳,谢谢 qq邮箱 3163487798@qq.com
huhailong520 2016-06-23
  • 打赏
  • 举报
回复
自己搞定了结贴了。就在上面定义一个静态变量 Dictionary<string, DateTime> 。然后在心跳包方法里面给Dictionary 赋值,没有当前key就新加有的话就改变他的时间。然后在定时器里面检测 Dictionary 变量,当前时间减去每个key对应的时间 如果大于1分钟(我这里是按一分钟来算的),就认为他是掉线了 同时剔除当前这个key值信息,就好了。
黑娃 2016-06-23
  • 打赏
  • 举报
回复
心跳其实很单纯,你就当常规数据一样去收,收到后更新一下对应clinet的最后活动时间即可,不需要去数据库捣腾。另外你需要启动一个清理后台线程,定期检查所有client是不是假死了(最后活动时间过于久远),假死了就主动断开,这也是心跳的目的。
Poopaye 2016-06-23
  • 打赏
  • 举报
回复
考虑心跳包之前还是把现有代码给整理整理吧
lshfong 2016-06-23
  • 打赏
  • 举报
回复
定时发一个约定的标识符给对方,说明你还活着,这就是心跳包
jakwin 2016-06-23
  • 打赏
  • 举报
回复
你不断地 new Thread 你不怕电脑挂了吗?同步socket应该用线程池操作吧!
戈壁上的月光 2016-06-23
  • 打赏
  • 举报
回复
服务端对每一个连接上的客户端SOCKET进行管理,每收到一个心跳包更新对应的客户端SOCKET超时判断,另外实时监控客户端SOCKET,有连接超时即中断连接并清理。
xian_wwq 2016-06-22
  • 打赏
  • 举报
回复
心跳包本质是当客户端无业务数据时,发送标识包,以维持长连接; 对于server来说,要管理的对象不能是个“裸”的socket,而是要抽象下,是基于socket的客户端session 这session中除了socket,大多数情况下还要记录身份验证信息,最后一次接收数据的时间等, 同时server侧要有超时剔除逻辑,当session的操作时间timeout后, 将相应的socket关闭,释放资源
  • 打赏
  • 举报
回复
最后一点,如果这些代码是你靠“蒙”弄来的,那么你要从头重新学编程。否则就要先看懂自己的白纸黑字写的够明白的代码。 这对你有好处。
  • 打赏
  • 举报
回复
首先,你不能在 int length = sokClient.Receive(arrMsgRec) 语句之后立刻去搞什么 Encoding.GetString(....),因为tcp 是会粘包和分包的,你应该是等到1次或者多次 Receive 之后、看到了消息结束标志之后(有时候粘包的话,那么消息结束标志之后还跟着下一个消息的一部分内容),才来把这个从缓冲中消息取出来并进行处理。 第二,你的 handleData 方法本来就是处理各种消息的。刚一看你的问题描述,给我说“蒙了”,我说“这个人怎么会说通讯是到数据库表存数据”呢?看了你这个方法我知道了,你根本没有搞懂自己写了什么代码。这里就是处理消息啊,你就按照你们的约定返回呗。比如说约定要返回“OK”,那么就向 sokClient 写入包含了“OK”的消息(的二进制编码)呗。 第三,不要滥用 Encoding.Default。这个在不同的机器上、不同的操作系统上,返回结果不同。所以用这个 Default,看上去挺高大上(通用),实际上是滥用,你根本不确定自己再干什么。所以使用 UTF8 或者 gb2312 都可以,但是不要滥用 Default。 第四,handleData 通常应该异步多线程来实现,例如写
ThreadPool.QueueUserWorkItem(h =>handleData(strMsg, sokClient));
,这样可以释放 I/O 线程,从而让它提前处理 sokClient 的后边的消息。当然,这是假设你对于长连接的通讯方式,知道信令处理完然后返回结果的次序跟收到信令的次序可能有所改变的情况下。因为有的任务可能处理要200毫秒,而有的可能只要3毫秒,那么当客户端以次序1、2、3、4、5来发送消息时,可能受到反馈的次序是对应着1、4、2、5、3消息的。 如果你不想处理长连接的业务逻辑,那么就不要写成一个长连接的通讯程序。

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧