QTcpSocket断网重连(二)

上一篇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)
            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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章