QTcpSocket客户端自动重连

10

我正在尝试编写一段代码,使用QTcpSocket定期尝试连接到服务器,直到服务器准备好。当服务器下线时,客户端应该自动周期性地尝试重新连接,直到它再次上线或用户手动关闭程序。

我已经订阅了QTcpSocket的 connected 和 error 信号。当我捕获到错误信号时,我基本上会再次调用 connectToHost 方法。

我的代码定期尝试连接到主机,直到服务器准备就绪(这部分正常工作)。然而,问题是当服务器下线时它永远无法重新连接。当连接断开时,我像预期的那样得到 RemoteHostClosedError 错误。但是,在同一个方法中(我在其中捕获 RemoteHostClosedError)再次调用 connectToHost 方法后,我什么也没有得到。甚至 QTcpSocket 对象也没有发出错误信号。

我在下面给出了我的代码。

TcpServerConnector::TcpServerConnector( SocketSettings socketSettings, QObject* parent)
: QObject(parent), socket(new QTcpSocket())
{
    this->connect(this->socket, SIGNAL(connected()), this, SLOT(connectionSuccess_Handler()), Qt::DirectConnection);
    this->connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError_Handler(QAbstractSocket::SocketError)), Qt::DirectConnection);
}


void TcpServerConnector::connectionError_Handler( QAbstractSocket::SocketError error )
{
    switch (error)
    {
    case QAbstractSocket::AddressInUseError:
        this->logger.log(LogLevel::ERR, "SOCKET ERROR: Address is already in use");
        break;
    case QAbstractSocket::ConnectionRefusedError:
        this->logger.log(LogLevel::ERR, "SOCKET ERROR: Connection refused");
        break;
    case QAbstractSocket::HostNotFoundError:
        this->logger.log(LogLevel::ERR, "SOCKET ERROR: Host not found");
        break;
    case QAbstractSocket::RemoteHostClosedError:
        this->logger.log(LogLevel::ERR, "SOCKET ERROR: Remote host closed");            
        break;  
    }


    this->socket->abort();
    this->socket->close();
    this->logger.log(LogLevel::DEBUG, "Reconnecting...");
    SystemUtil::sleepCurrentThread(1000);
    this->socket->connectToHost(ip_address, port);
}

在调用connectToHost方法之前和之后,我会检查QTcpSocket的状态(我在这里提供的最后一行)。在调用connectToHost之前,状态为未连接状态,调用之后状态变为连接状态。这没有什么意外。但是,她既无法连接到服务器,也无法发出错误信号。

有什么想法吗?

注意:第一次内部调用QTcpSocket的connectToHost方法。


不要从错误处理程序插槽重新连接。 "当发出此信号时,套接字可能尚未准备好进行重新连接尝试。" [Qt文档] (http://doc.qt.io/qt-5/qabstractsocket.html#error-2) - bartolo-otrit
5个回答

6

对于可能遇到类似情况的人,QTcpSocket的重置方法解决了问题。


当你解决问题时,可以将自己的答案标记为正确的。这样搜索该问题的人就能快速找到解决方案。 - hg.
4
请发布您的解决方案...谢谢;) - Alireza Soori

1
我遇到了这种情况,以下是解决方法:
    connect(&tcpClient, SIGNAL(disconnected()), SLOT(ReconnectToHost()));


    void ReconnectToHost(){tcpClient.connectToHost(theServerAddress, port);}

1
断开的信号在哪里?它是默认的还是用户定义的? - Sharath

1

我遇到了这样的问题。 我的错误在于我尝试从我的类的槽中使用QTcpSocket::connectToHost(),并连接到QTcpSocket::error()信号。最终我在这个post中找到了解决方法。

如果我没记错的话,问题在于你不能从这个槽内部重新连接,因为在QTcpSocket::error()信号发出后,重要的事情就会发生,控制流从你的处理程序返回到发出此信号的QTcpSocket的方法,或者你以某种方式破坏了套接字的逻辑。

不是优雅的,但仍然是一行代码的解决方案是,在调用handle_socket_error()槽之后,调用QMetaObject::invokeMethod(m_socket, "connectToHost", Qt::QueuedConnection);

请注意,如果您在自定义方法上调用QMetaObject::invokeMethod,它必须被注册为一个槽。

更新:我很抱歉,但这个问题在Qt的QAbstractSocket::error()信号文档中有提到。


0

socket.h:

    private slots:
    void reConnectServer(QAbstractSocket::SocketError error);
    private:
    QTcpSocket *mSocket;
    QString mHostname;
    int mPort;
  

socket.cpp:

    connect(&mSocket,&QTcpSocket::errorOccurred,this,&WorkerClient::reConnectServer);
    void Socket::reConnectServer(QAbstractSocket::SocketError error)
    {
    qDebug()<<error;//e.g.,QAbstractSocket::RemoteHostClosedError
    if(!mSocket.waitForConnected(10000)){
    mSocket.connectToHost(mHostname,mPort);
    }
    }

不要忘记在 main.cpp 中添加这个:

    qRegisterMetaType<QAbstractSocket::SocketError>();

枚举 QAbstractSocket::SocketError:

该枚举描述了可能发生的套接字错误。 https://doc.qt.io/qt-5/qabstractsocket.html#SocketError-enum


0
我使用计时器来解决这个问题,目前为止效果很好。
QTcpSocket _client;
QTimer _timer;

//when server off, try to connect periodically
connect(&_timer, &QTimer::timeout, this, [&]{_client.connectToHost(QHostAddress("127.0.0.1"),7920);});
_timer.setInterval(5000);
_timer.start();

//when connected, stop trying
connect(&_client, &QTcpSocket::connected, this, [&]{
    ((QTcpSocket *)QObject::sender())->write("connected");
    _timer.stop();
});

//when disconnected, try again
connect(&_client, &QTcpSocket::disconnected, this, [&]{_timer.start();});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接