国家与QTcpSocket始终连接,甚至拔掉以太网线(QTcpSocket state always

2019-06-24 04:06发布

我有一个和与QTcpSocket我读成一个圈。 每一个完整的数据包已经被阅读,或出现了一个错误的时间,我手动检查插座的状态内循环,用:

    while(true){
    if(socket->state()==QAbstractSocket::ConnectedState){
        qDebug()<<"Socket status: connected. Looking for packets...";
        if(socket->waitForReadyRead(2000)){
        //...
    }

当我执行程序去,一旦连接,并在循环开始,它总是打印qDebug()<<"Socket status: connected. Looking for packets..." ; 然后在stucks waitForReadyRead直到一些数据已准备好被读取。

问题是,没有检测到断线。 如果我从网络断开OS选项,否则即使我拔掉网线,它的行为是一样的:套接字状态等于QAbstractSocket::ConnectedStat E,所以它的推移,但没有接受,当然任何事情。

我还试图检测连接断开disconnected()信号(拳头连接之后),以重新连接功能:

// Detect disconnection in order to reconnect
    connect(socket, SIGNAL(disconnected()), this, SLOT(reconnect()));

void MyClass::reconnect(){
    qDebug()<<"Signal DISCONNECTED emitted. Now trying to reconnect";
    panelGUI->mostrarValueOffline();
    socket->close();
    prepareSocket((Global::directionIPSerialServer).toLocal8Bit().data(), 8008, socket);
    qDebug()<<"Reconnected? Status: "<<socket->state();
}

但信号也决不emited,因为永远不会执行该代码。 这是合乎逻辑的,因为它看起来像座状态总是ConnectedState

如果我再次插入,连接恢复并重新开始接收数据,但我确实想发现断开,以示“断开连接”的GUI。

为什么表现与QTcpSocket这样,我怎么能解决这个问题?

编辑:我在类的构造函数创建套接字,然后调用初始化函数prepareSocket:

socket = new QTcpSocket();
socket->moveToThread(this);

bool prepareSocket(QString address, int port, QTcpSocket *socket) {
    socket->connectToHost(address, port);
    if(!socket->waitForConnected(2000)){
        qDebug()<<"Error creating socket: "<<socket->errorString();
        sleep(1);
        return false;
    }
    return true;
}

Answer 1:

终于找到这个解决方案的Qt论坛 :

如果没有数据被用于在一定的同时交换,TCP将开始(与设置为当前序列号少一个确认号基本上,ACK段)发送保持活动段。 其它对等然后用另一确认进行回复。 如果该确认是不是一个特定数量的探针段内接收到,则连接被自动删除。 小问题是,内核启动后2小时,因为当连接空闲发送保活段! 因此,您需要更改这个值(如果您的操作系统允许),或在您的协议,实现自己保持活动的机制(如许多协议来完成,如SSH)。 Linux允许你使用setsockopt的去改变它:

int enableKeepAlive = 1;
int fd = socket->socketDescriptor();
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));

int maxIdle = 10; /* seconds */
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));

int count = 3;  // send up to 3 keepalive packets out, then disconnect if no response
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &count, sizeof(count));

int interval = 2;   // send a keepalive packet out every 2 seconds (after the 5 second idle period)
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));


Answer 2:

我一直面临着一个QT客户端应用程序类似的问题。 基本上我与定时器,信号和槽处理它。 当应用程序启动时,它开始4秒checkConnectionTimer。 每4秒计时器到期时,如果客户端套接字状态!= AbstractSocket ::连接或连接,它尝试与clientSocket-> connectToHost连接

当插座信号“连接()”,它开始5秒的服务器心跳定时器。 服务器应该发送一个字节心跳消息每4秒它的客户。 当我心跳(或readyRead暗示任何类型的消息()),我重新启动心跳计时器。 所以,如果心跳计时器不断有超时,我认为连接将下降并呼吁clientSocket->disconnectFromHost ();

这是工作非常好各种不同类型的断开的服务器上,优雅或以其他方式(猛拉电缆)。 是的,它需要自定义心跳类型的东西,但在一天结束时它是最快捷,最便携的解决方案。

我并不热衷于在内核设置KEEPALIVE超时。 这样,其更便于携带。 在构造函数:

connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readMessage()));
connect(clientSocket, SIGNAL(connected()), this, SLOT(socketConnected()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
connect(heartbeatTimer, SIGNAL(timeout()), this, SLOT(serverTimeout()));
...
// Other Methods

void NetworkClient::checkConnection(){
    if (clientSocket->state() != QAbstractSocket::ConnectedState &&
            clientSocket->state() != QAbstractSocket::ConnectingState){
        connectSocketToHost(clientSocket, hostAddress, port);
    } 
}

void NetworkClient::readMessage()
{
    // Restart the timer by calling start.
    heartbeatTimer->start(5000);
    //Read the data from the socket
    ...
}

void NetworkClient::socketConnected (){
    heartbeatTimer->start(5000);
}

void NetworkClient::socketDisconnected (){
    prioResponseTimer->stop();
}

void NetworkClient::serverTimeout () {
    clientSocket->disconnectFromHost();
}


Answer 3:

试试这个信号槽连接:

connect(this, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState)));

在插槽实现:

void TCPWorker::onStateChanged(QAbstractSocket::SocketState socketState ){
qDebug()<< "|GSTCPWorkerThread::onStateChanged|"<<socketState;
...}

我有同样的问题,而是你的问题(总是连接),我有延时4-5秒接收断开信号,unplugget以太网线后。

仍然在寻找解决方案,后期的答案,如果找到。



Answer 4:

尝试在Qt的我的客户的模板:

class Client: public QTcpSocket {
   Q_OBJECT
public:
    Client(const QHostAddress&, int port, QObject* parent= 0);
    ~Client();
    void Client::sendMessage(const QString& );
private slots:
    void readyRead();
    void connected();
public slots:
    void doConnect();
};

CPP的:

void Client::readyRead() {

    // if you need to read the answer of server..
    while (this->canReadLine()) {
    }
}

void Client::doConnect() {
    this->connectToHost(ip_, port_);
    qDebug() << " INFO : " << QDateTime::currentDateTime()
            << " : CONNESSIONE...";
}

void Client::connected() {
    qDebug() << " INFO : " << QDateTime::currentDateTime() << " : CONNESSO a "
            << ip_ << " e PORTA " << port_;
    //do stuff if you need
}


void Client::sendMessage(const QString& message) {
    this->write(message.toUtf8());
    this->write("\n"); //every message ends with a new line
}

我省略了一些代码,构造和插槽连接..尝试与这一点,如果它不将不起作用,也许有不对的服务器端..



文章来源: QTcpSocket state always connected, even unplugging ethernet wire