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

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