总第22篇
在开发网络通信系统的过程中,有时客户端必须要知道网络的连接状态,而客户端与服务器断开连接的因素有很多。本文将综合分析各种情况,在此基础上介绍心跳包的使用与代码实现。
1.不同的网络断开连接情况
在常见的C/S结构系统中,网络断开连接状况主要可分为下面六种:客户端网线断开;
客户端网络断开;
客户端通过Http代理连接服务器,代理机器断开代理;
客户端通过Http代理连接服务器,代理机器网络断开;
客户端通过Http代理连接服务器,代理机器的网线断开;
服务器断开;
对于上面的六种情况,又可从连接服务器之前和连接服务器之后两方面来分析。
连接服务器之前:
对于第1种情况【客户端网线断开】,此时用socket调用connectToHost()方法连接服务器会立即触发 QTcpSocket的error信号, 我们可以绑定相应的信号槽去处理连接失败的结果。
对于第2-6种情况,此时用socket调用connectToHost()方法连接服务器并不会立即触发QTcpSocket的error信号, 而是经过40s以上的连接等待超时后才发出error信号。
连接上服务器之后:
对于第1种情况【客户端网线断开】,此时socket不会发送error信号,也不会发送disconnect信号, 这是因为网线是属于物理链路层的,tcp无法觉察到,socket仍处于连接状态。
对于第2-3种情况, 此时socket会立即触发error信号。
对于第4-5种情况,此时socket会等待30s左右发送error信号。
对于第6种情况, 此时socket会发送disconnect信号,可以绑定相应的槽去处理服务器断开的情况。
2.心跳包的使用与实现
对于某些场景下,客户端与服务器断开后,需要立即知道连接状态并做相应的处理,而不是等待几十秒后才有信号通知。要实现这种功能,一种比较好的方法就是用心跳包来实现。
发送心跳包,即客户端每隔一段时间发送一条报文,报文不需要附带具体内容,只 需要让服务端知道这是一条心跳报文,并回发一条消息,客户端收到这条消息后,就得知其与服务器保持连接的状态。
下面将心跳的代码实现示例出来,以便参考。这里会单独写一个心跳类TcpHeart。
//这是TcpHeart的头文件#ifndef TCPHEART_H#define TCPHEART_H
#include #include
class TcpHeart:public QObject
{
Q_OBJECT
public:
TcpHeart(QObject *parent = 0)
~TcpHeart(void);
void StartHeartTimer();
signals:
void SigHeartBad();
void SigHeartReq();
private slots:
void SlotTimeout();
void SlotHeartBack();
private:
QTimer *m_heart_timer;
int m_count;
};
#endif
//这是TcpHeart的实现文件
#include "tcpheart.h"
TcpHeart::TcpHeart(QObject *parent):QObject(parent)
{
m_heart_timer = new QTimer(this);
m_count = 0;
connect(m_heart_timer, SIGNAL(timeout()), this, SLOT(SlotTimeout()));
}
TcpHeart::~TcpHeart(void)
{
}
void TcpHeart::StartHeartTimer()
{
m_heart_timer->start(2000);
}
void TcpHeart::SlotTimeout()
{
if(m_count > 2)
{
m_count = 0;
m_heart_timer->stop();
emit SigHeartBad();
return;
}
m_count++;
emit SigHeartReq();
}
void TcpHeart::SlotHeartBack()
{
m_count = 0;
}
在客户端,当连接成功服务器后,启动心跳定时器:heart->StartHeartTimer(); 实现其socket的读写函数如下:
void SlotHeartReadyRead()
{
QByteArray heart_bytes = heart_socket->readAll();
if(QString(heart_bytes)== "OK") //连接成功从服务端读取OK字符 {
heart = new TcpHeart;
//开始心跳请求 heart->StartHeartTimer();
connect(heart, SIGNAL(SigHeartReq()), this, SLOT(SlotWriteHeartSocket()));
connect(this, SIGNAL(SigHeartBack()), heart, SLOT(SlotHeartBack()));
//掉线后的处理 connect(heart, SIGNAL(SigHeartBad()), this, SLOT(SlotHeartBad()));
}
//心跳反馈 if(QString(heart_bytes) == "HEART_BACK")
emit SigHeartBack();
}
void SlotHeartBad()
{
qDebug()<
//可以添加心跳失败的处理}
void SlotWriteHeartSocket()
{
heart_socket->write("HEART");
}
在服务器端,当有新的客户端连接成功后,直接向客户端写OK心跳字符,即heart_socket->write("OK"),并启动相应的定时器。其实现读取socket的函数如下:
void SlotReadHeartSocket()
{
QByteArray bytes = heart_socket->read(5); //注意这里要读取5个字节,而不是随意读取 if(QString(bytes) == "HEART")
{
heart_socket->write("HEART_BACK");
heart_count = 0;
}
}
本文到此结束!
如果对你有帮助,请随手 点个赞 或 点喜欢! 收藏不点赞,感觉不仁道......
=======================================================
欢迎【关注作者、私信作者】。我们一起交流一起进步。
=======================================================