QT 中Socket客户端与服务器异常断开后重连
转载地址: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,然后我关掉服务器,于是客户端便进行重连...,后边重开服务器,客户端便重连成功。
上边是把定时器事件给屏蔽了,使用定时器来实现,也可以把定时器屏蔽,使用定时器事件进行重连,具体视项目情况而定。