上一篇QTcpSocket断网重连地址:QTcpSocket断网重连(一)
在第一篇中Linux下有一个潜在的bug,不会影响到客户端,但是对服务器端会有一定影响,在服务器端物理断网的情况下,会出现一旦服务器恢复网络后客户端断网重连时,会出现服务器端有多个端口连接情况。但是客户端这边检查只有一次连接,所以这个现在只能猜测出现bug原因。
通过这一篇中代码的测试,有以下猜测:
- abort()-----------这个函数执行时,不会清除上一次连接端口,但是官方对这个函数的解释是:终止当前连接并重置套接字。与disconnectFromHost()不同,此函数立即关闭套接字,丢弃写缓冲区中的任何挂起数据。
- 服务器端物理断网后,QTcpSocket本身是检测不到断网情况的,根据段时间后没有连上,那么开始不断连接,连接信号发出去后,本地处于挂起状态没有销毁掉,上一次连接信息继续发出连接请求导致出现多个端口连接情况
下面通过代码讲解实现思路:
#ifndef TCPSOCKETCLIENT_H
#define TCPSOCKETCLIENT_H
#include <QObject>
#include <QTcpSocket>
#include <QTimer>
class TcpSocketClient : QObject
{
Q_OBJECT
public:
TcpSocketClient();
~TcpSocketClient();
void startConnect(const QString& strAddressIP, quint16 iPort);
private:
QTcpSocket *m_TcpSocket;
bool b_isConnectState;
QString m_strAddressIP;
quint16 m_iPort;
QTimer *m_timerConnect;
QTimer *m_timerSend;
private slots:
void onConnect();
void onDisConnect();
void onErrorString(QAbstractSocket::SocketError errorString);
void onRecvData();
void onSendData();
};
#endif // TCPSOCKETCLIENT_H
#include "tcpsocketclient.h"
#include <QDebug>
TcpSocketClient::TcpSocketClient()
: b_isConnectState(false)
, m_strAddressIP("127.0.0.1"), m_iPort(0)
{
m_TcpSocket = new QTcpSocket();
connect(m_TcpSocket, SIGNAL(connected()), this, SLOT(onConnect()));
connect(m_TcpSocket, SIGNAL(disconnected()) , this, SLOT(onDisConnect()));
connect(m_TcpSocket, SIGNAL(readyRead()), this, SLOT(onRecvData()));
connect(m_TcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(onErrorString(QAbstractSocket::SocketError)), Qt::DirectConnection);
m_timerConnect = new QTimer();
connect(m_timerConnect, &QTimer::timeout, [=](){
if(b_isConnectState)
return;
// 这一部分又问题,实际状态有很多种
//if(m_TcpSocket->state() == QAbstractSocket::ConnectingState)
// 改为 等于未连接状态才开始连接,杜绝因为其他原因导致的连接
if(m_TcpSocket->state() != QAbstractSocket::UnconnectedState)
return;
m_TcpSocket->connectToHost(m_strAddressIP, m_iPort);
});
m_timerSend = new QTimer();
connect(m_timerSend, &QTimer::timeout, [=](){
onSendData();
});
}
TcpSocketClient::~TcpSocketClient()
{
m_TcpSocket->abort();
}
void TcpSocketClient::startConnect(const QString &strAddressIP, quint16 iPort)
{
m_strAddressIP = strAddressIP;
m_iPort = iPort;
m_timerConnect->start(1000);
}
void TcpSocketClient::onConnect()
{
b_isConnectState = true;
qDebug() << "onConnect";
m_timerConnect->stop();
m_timerSend->start(200);
}
void TcpSocketClient::onDisConnect()
{
b_isConnectState = false;
qDebug() << "onDisConnect";
m_timerConnect->start(1000);
m_timerSend->stop();
}
void TcpSocketClient::onErrorString(QAbstractSocket::SocketError errorString)
{
qDebug() << errorString;
}
void TcpSocketClient::onRecvData()
{
if(m_TcpSocket->state() != QAbstractSocket::ConnectedState)
return;
if(m_TcpSocket->bytesAvailable() < 0)
{
m_TcpSocket->disconnectFromHost();
m_TcpSocket->waitForDisconnected(3000);
}
while (m_TcpSocket->bytesAvailable() > 0)
{
QByteArray arrayData;
arrayData.resize((int)m_TcpSocket->bytesAvailable());
m_TcpSocket->read(arrayData.data(), arrayData.size());
QString str_tcp_receive = QString::fromLocal8Bit(arrayData);
qDebug() << str_tcp_receive;
}
}
void TcpSocketClient::onSendData()
{
if(m_TcpSocket->state() != QAbstractSocket::ConnectedState)
return;
QString strData = "123";
qint64 iSendDataLength = m_TcpSocket->write(strData.toUtf8().data(), strData.length());
if(!m_TcpSocket->flush() || iSendDataLength < 0)
{
m_TcpSocket->disconnectFromHost();
m_TcpSocket->waitForDisconnected(3000);
}
}
注意:
1、在主线程中使用要注意QTcpSocket
中的所有 wait****
函数,所有的这类函数都会导致阻塞主线程,使用时候需要注意
2、如果有断不开的情况,一般是因为onSendData
函数部分,一直在发送导致,可以主动触发disconnected
信号
这是一个简单示例,有需要的可以下载查看:https://download.csdn.net/download/bloke_come/12346214