转载地址:https://blog.csdn.net/lms1008611/article/details/81507161
在现在的项目开发中,经常要使用TCP/IP协议来进行通讯,但有时候与服务器端的链接由于网络问题导致连接异常或断开,这就需要我们的软件能自动重连,在Linux中,我们的思维一般是通过心跳包来监控连接是否断开,有时候还单独开一个线程,但是在QT中,就变得简单多了,当连接异常断开时,会触发相应的信号,我们只要在这个信号对应的槽函数中做重连处理就可以了,不需要另开线程也不需要心跳包。由于网上查的QT重连服务器端,大多都是通过建立的线程去实现,我觉得比较麻烦,这里就记录下我自己的思路:使用定时器QTimer或定时器事件QTimerEvent,来实现重连,当当前的连接断开时,QT便会发送 disconnected()信号,我们在这个信号对应的槽函数中开启定时器,重连的操作就放在定时器对应的槽函数中执行(或重写的定时器事件中执行),当重连成功后,QT会发送connected()信号,此时我们在其对应的槽函数中关闭定时器即可。
下边直接来贴代码,我们是建了一个简单的clientt类,来做一个Socket客户端,首先是头文件client.h文件
-
#ifndef CLIENT_H -
#define CLIENT_H -
#include <QtWidgets/QWidget> -
#include <QtNetwork> -
#include <QtNetwork/QTcpSocket> -
#include <QLineEdit> -
#include <QTextEdit> -
#include <QPushButton> -
#include <QLabel> -
#include <QTimerEvent> -
#include <QTimer> -
class Client : public QWidget -
{ -
Q_OBJECT -
public: -
Client(QWidget *parent = 0); -
~Client(); -
private: -
//方式一:使用定时器事件实现socket重连 -
int m_TimerID; //定时器事件ID -
void timerEvent(QTimerEvent * event); //需要重写改定时器事件函数 -
//方式二:使用定时器实现重连 -
QTimer m_Timer; -
protected: -
void init(); //UI初始化 -
void newTCPConnect(); //建立一个新连接 -
private slots: -
void clientReadData(); //几个Socket连接相关的槽函数 -
void clientConnected(); -
void clientDisconnected(); -
void clientError(QAbstractSocket::SocketError socketError); -
void clientStateChange(QAbstractSocket::SocketState socketState); -
void onConnectButtonClicked(); -
void slotTimeOut(); -
private: -
bool m_IsConnected; -
QTcpSocket *tcpSocket; -
QPushButton m_ConnectButton; -
QLabel m_IPLabel; -
QLabel m_PortLabel; -
QLineEdit m_IPEdit; -
QLineEdit m_PortEdit; -
QTextEdit m_TextEdit; -
}; -
#endif // CLIENT_H
下边是client.cpp文件
-
#include "Client.h" -
#include <QHostAddress> -
#include <QFormLayout> -
#include <QHBoxLayout> -
#include <QVBoxLayout> -
#include <QDebug> -
Client::Client(QWidget *parent) : QWidget(parent), m_IsConnected(false) -
{ -
this->setFixedSize(500, 300); -
init(); -
} -
void Client::init() -
{ -
m_IPLabel.setParent(this); -
m_IPLabel.setText("IP"); -
m_PortLabel.setParent(this); -
m_PortLabel.setText("Port"); -
m_IPEdit.setParent(this); -
m_IPEdit.setText("127.0.0.1"); -
m_PortEdit.setParent(this); -
m_PortEdit.setText("5000"); -
m_ConnectButton.setParent(this); -
m_ConnectButton.setText("connect"); -
m_TextEdit.setParent(this); -
QFormLayout *fLayout1 = new QFormLayout; -
fLayout1->addRow(&m_IPLabel, &m_IPEdit); -
QFormLayout *fLayout2 = new QFormLayout; -
fLayout2->addRow(&m_PortLabel, &m_PortEdit); -
QHBoxLayout *hLayout = new QHBoxLayout; -
hLayout->addLayout(fLayout1); -
hLayout->addLayout(fLayout2); -
hLayout->addWidget(&m_ConnectButton); -
QVBoxLayout *vLayout = new QVBoxLayout; -
vLayout->addLayout(hLayout); -
vLayout->addWidget(&m_TextEdit); -
this->setLayout(vLayout); -
tcpSocket = new QTcpSocket(this); -
connect(&m_ConnectButton, SIGNAL(clicked()), this, SLOT(onConnectButtonClicked())); -
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(clientReadData())); -
connect(tcpSocket, SIGNAL(connected()), this, SLOT(clientConnected())); -
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); -
connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(clientStateChange(QAbstractSocket::SocketState))); -
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(clientError(QAbstractSocket::SocketError))); -
connect(&m_Timer, SIGNAL(timeout()), this, SLOT(slotTimeOut())); -
} -
void Client::newTCPConnect() -
{ -
tcpSocket->abort(); -
QHostAddress address = QHostAddress(m_IPEdit.text()); -
unsigned int port = m_PortEdit.text().toInt(); -
tcpSocket->connectToHost(address, port); -
if (!tcpSocket->waitForConnected(3000)) //连接时长为3s,超过3秒连不上则输出错误信息 -
{ -
} -
} -
//接收数据 -
void Client::clientReadData() -
{ -
QString msg = "\nrecieve msg : " + tcpSocket->readAll(); -
m_TextEdit.append(msg); -
tcpSocket->write("GET"); -
} -
//连接成功是时调用 -
void Client::clientConnected() -
{ -
m_Timer.stop(); //连接成功后定时器停止 -
//killTimer(m_TimerID); //连接成功后终止对应ID的定时器事件 -
m_IsConnected = true; -
QString msg = "server IP : " + tcpSocket->peerAddress().toString(); -
m_TextEdit.append(msg); -
msg = "server Port : " + QString::number(tcpSocket->peerPort()); -
m_TextEdit.append(msg); -
m_ConnectButton.setText("disconnect"); -
m_ConnectButton.setStyleSheet("background-color: green"); -
//当重连成功时,可以根据具体情况恢复软件的一些工作 -
} -
//连接断开时调用 -
void Client::clientDisconnected() -
{ -
m_Timer.start(2000); //连接断开时开启定时器,定时时间为2s -
//m_TimerID = startTimer(2000); //连接断开时开始一个定时器事件,并将ID赋给m_TimerID -
m_IsConnected = false; -
m_ConnectButton.setText("connect"); -
m_ConnectButton.setStyleSheet("background-color: red"); -
//当连接断开时,可以根据具体情况决定是否停止软件当前的一些工作,比方暂停测试什么的 -
} -
//获取socket错误信息 -
void Client::clientError(QAbstractSocket::SocketError socketError) -
{ -
m_IsConnected = false; -
tcpSocket->close(); -
} -
//连接状态发生改变时获取其状态 -
void Client::clientStateChange(QAbstractSocket::SocketState socketState) -
{ -
#if 0 -
if (socketState == QAbstractSocket::UnconnectedState) -
{ -
m_TextEdit.append("clientState : UnconnectedState"); -
} -
else if (socketState == QAbstractSocket::HostLookupState) -
{ -
m_TextEdit.append("clientState : HostLookupState"); -
} -
else if (socketState == QAbstractSocket::ConnectedState) -
{ -
m_TextEdit.append("clientState : ConnectedState"); -
} -
else if (socketState == QAbstractSocket::ConnectingState) -
{ -
m_TextEdit.append("clientState : ConnectingState"); -
} -
else if (socketState == QAbstractSocket::ClosingState) -
{ -
m_TextEdit.append("clientState : ClosingState"); -
} -
#endif -
} -
void Client::onConnectButtonClicked() -
{ -
m_TextEdit.append(""); -
if (m_ConnectButton.text() == "disconnect") -
{ -
tcpSocket->disconnectFromHost(); -
} -
else if(m_ConnectButton.text() == "connect") -
{ -
newTCPConnect(); -
} -
} -
void Client::timerEvent(QTimerEvent * event) -
{ -
if (event->timerId() == m_TimerID) //在定时器事件中重连服务器 -
{ -
if (!m_IsConnected) -
{ -
m_TextEdit.append(QString::fromLocal8Bit("重连服务器...")); -
newTCPConnect(); -
} -
} -
} -
//使用定时器来重连服务器 -
void Client::slotTimeOut() -
{ -
if (!m_IsConnected) -
{ -
m_TextEdit.append(QString::fromLocal8Bit("重连服务器...")); -
newTCPConnect(); -
} -
} -
Client::~Client() -
{ -
}
主程序中直接使用这个类:
-
#include "Client.h" -
#include <QtWidgets/QApplication> -
int main(int argc, char *argv[]) -
{ -
QApplication a(argc, argv); -
Client w; -
w.show(); -
return a.exec(); -
}
编译运行:
刚开始与服务器端正常连接并接收数据hello sokect,然后我关掉服务器,于是客户端便进行重连...,后边重开服务器,客户端便重连成功。
上边是把定时器事件给屏蔽了,使用定时器来实现,也可以把定时器屏蔽,使用定时器事件进行重连,具体视项目情况而定。