使用Qtcpsocket中的flush()方法后导致release版本运行不稳定问题

时间:2022-07-13 20:38:15
如题,使用Qt做的客户端启动后有两个线程,一个是主线程,一个是发送心跳线程,两线程使用同一个全局的Socket;
Socket每次write()后使用flush()清空缓存使消息马上发送到服务端,否则debug版本会出现心跳不及时发送现象;
除此之外debug版本比较稳定。现在测试release版本时,发现客户端运行一段时间后(半个小时左右,不做任何操作,程序内部会每隔4秒向服务端发送一次心跳)就会出现runtime error,试过很多方法都没有效果,但是发现把每次write()完的flush()操作注释掉以后就比较稳定。请问flush()是否会导致程序不稳定?

6 个解决方案

#1


flush不可能会让它不稳定的,这个你要绝对相信的.
 这里很有可能是你的线程不安全引起的,,Socket貌似不能跨线程使用的吧.

#2


引用 1 楼 n7zj0x8 的回复:
flush不可能会让它不稳定的,这个你要绝对相信的.
 这里很有可能是你的线程不安全引起的,,Socket貌似不能跨线程使用的吧.

可能flush不是引起问题的真正原因,但是注释掉以后确实变得稳定了。我在使用socket时做了互斥,我们的框架设计是登陆和心跳一定要使用同一个socket。

#3


哎...我猜我肯定解释不清楚,如果你贴代码,到可以看下.
socket貌似只能工作在一个线程里面..你用两个线程,里终也是合并到一个线程工作.
还有就是如果你用Qt写代码的话,我可以很确定的说,你可能一辈子也用不到互斥锁了.Qt信号槽就可以保证线程安全

#4


引用 3 楼 n7zj0x8 的回复:
哎...我猜我肯定解释不清楚,如果你贴代码,到可以看下.
socket貌似只能工作在一个线程里面..你用两个线程,里终也是合并到一个线程工作.
还有就是如果你用Qt写代码的话,我可以很确定的说,你可能一辈子也用不到互斥锁了.Qt信号槽就可以保证线程安全

线程是用Windows的API创建的

QTcpSocket* g_tcpSocket = new QTcpSocket();
HANDLE g_handleHeartBeat = CreateThread(NULL, 0, RunHeartBeat, g_Client, 0, NULL); // 创建心跳线程
DWORD WINAPI RunHeartBeat(LPVOID param)
{
    WaitForSingleObject(g_hMutex, INFINITE);
    Request request; // 需要向服务端发送的内容
    //.....填写request
    int nleft, nbytes;
    char* ptr = (char*)&request;

    nleft = 12;  // 需要发送的长度
     
    for (; nleft  > 0; )
    {
        nbytes = g_tcpSocket->write(ptr, nleft);
        g_tcpSocket->flush();     // 注释掉这行以后release版本就稳定了,但是debug版本不会及时发出消息

        if (nbytes <= 0)
        {
                // .......
                 ReleaseMutex(g_hMutex);
                return -1;
        }
        nleft -= nbytes;
        ptr += nbytes;
    }
    ReleaseMutex(g_hMutex);
}

主线程基本是一样的代码。能帮忙看一下吗,多谢!

#5


引用 4 楼 YouNeverCanTell 的回复:
主线程基本是一样的代码。能帮忙看一下吗,多谢!

差点凌乱了..这混合编程用得....目测你的问题应该是混合编程引起的

我给你贴一个处理了write函数的QTcpSocket,这个socket被我移动到一个单独的线程里面去了,但它write函数是线程安全的.  如果你有什么其它的函数接口需要调用m_pQTcpSocket的,像我那样写一个信号一个槽,然后连接起来,间接调用...这样可以保证m_pQTcpSocket在一个线程里面被使用.
这里问题来了,你可能会觉得这样写很麻烦或者不习惯.这个没有办法.如果你要用windows线程或者编程思想,处理Qt
的东西,真的会很纠结.. 貌似QTcpSocket在不同的Qt线程里面,调用它会报错(QSocketNotifier: socket notifiers cannot be enabled from another thread)..这里你的为什么没有报错,我估计就是因为你是windows的线程原因..不知道我有没有说错. 
这里要么你使用windows的socket要么你使用Qt的线程..如果使用Qt的线程,又要说一堆...这个问题就真的复杂起来了....我只能帮你到这里了.


#ifndef MYTCPSOCKET_H
#define MYTCPSOCKET_H

#include <QTcpSocket>
#include <QThread>
#include <QDebug>
#include <QHostAddress>

class MyTcpSocket : public QThread
{
    Q_OBJECT
public:
    MyTcpSocket()
        : m_pQTcpSocket(new QTcpSocket())
    {
        this->start();
        this->moveToThread(this);
        m_pQTcpSocket->moveToThread(this);

        connect(this, SIGNAL(DoMyWrite(QByteArray)),
                this, SLOT(OnMyWrite(QByteArray)));
        connect(this, SIGNAL(DoMyConnect()),
                this, SLOT(OnMyConnectToHost()));
    }

    ~MyTcpSocket()
    {
        this->exit();
        this->wait(10 * 1000);
    }

    void myWrite(const char *data, qint64 len)
    {
        emit DoMyWrite(QByteArray(data, len));
    }

    void myConnectToHost()
    {
        emit DoMyConnect();
    }

signals:
    void DoMyWrite(const QByteArray &data);
    void DoMyConnect();

private slots:
    void OnMyWrite(const QByteArray &data)
    {
        qDebug() << "write" << QThread::currentThreadId();
        m_pQTcpSocket->write(data);
        m_pQTcpSocket->flush();
    }
    void OnMyConnectToHost()
    {
        qDebug() << "myConnect" << QThread::currentThreadId();
        m_pQTcpSocket->connectToHost(QHostAddress::LocalHost, 8811);
    }

private:
    QTcpSocket * const m_pQTcpSocket;
};

#endif // MYTCPSOCKET_H


#6


引用 5 楼 n7zj0x8 的回复:
Quote: 引用 4 楼 YouNeverCanTell 的回复:

主线程基本是一样的代码。能帮忙看一下吗,多谢!

差点凌乱了..这混合编程用得....目测你的问题应该是混合编程引起的

我给你贴一个处理了write函数的QTcpSocket,这个socket被我移动到一个单独的线程里面去了,但它write函数是线程安全的.  如果你有什么其它的函数接口需要调用m_pQTcpSocket的,像我那样写一个信号一个槽,然后连接起来,间接调用...这样可以保证m_pQTcpSocket在一个线程里面被使用.
这里问题来了,你可能会觉得这样写很麻烦或者不习惯.这个没有办法.如果你要用windows线程或者编程思想,处理Qt
的东西,真的会很纠结.. 貌似QTcpSocket在不同的Qt线程里面,调用它会报错(QSocketNotifier: socket notifiers cannot be enabled from another thread)..这里你的为什么没有报错,我估计就是因为你是windows的线程原因..不知道我有没有说错. 
这里要么你使用windows的socket要么你使用Qt的线程..如果使用Qt的线程,又要说一堆...这个问题就真的复杂起来了....我只能帮你到这里了.


#ifndef MYTCPSOCKET_H
#define MYTCPSOCKET_H

#include <QTcpSocket>
#include <QThread>
#include <QDebug>
#include <QHostAddress>

class MyTcpSocket : public QThread
{
    Q_OBJECT
public:
    MyTcpSocket()
        : m_pQTcpSocket(new QTcpSocket())
    {
        this->start();
        this->moveToThread(this);
        m_pQTcpSocket->moveToThread(this);

        connect(this, SIGNAL(DoMyWrite(QByteArray)),
                this, SLOT(OnMyWrite(QByteArray)));
        connect(this, SIGNAL(DoMyConnect()),
                this, SLOT(OnMyConnectToHost()));
    }

    ~MyTcpSocket()
    {
        this->exit();
        this->wait(10 * 1000);
    }

    void myWrite(const char *data, qint64 len)
    {
        emit DoMyWrite(QByteArray(data, len));
    }

    void myConnectToHost()
    {
        emit DoMyConnect();
    }

signals:
    void DoMyWrite(const QByteArray &data);
    void DoMyConnect();

private slots:
    void OnMyWrite(const QByteArray &data)
    {
        qDebug() << "write" << QThread::currentThreadId();
        m_pQTcpSocket->write(data);
        m_pQTcpSocket->flush();
    }
    void OnMyConnectToHost()
    {
        qDebug() << "myConnect" << QThread::currentThreadId();
        m_pQTcpSocket->connectToHost(QHostAddress::LocalHost, 8811);
    }

private:
    QTcpSocket * const m_pQTcpSocket;
};

#endif // MYTCPSOCKET_H



谢谢,改用定时器确实不会有这问题了。

#1


flush不可能会让它不稳定的,这个你要绝对相信的.
 这里很有可能是你的线程不安全引起的,,Socket貌似不能跨线程使用的吧.

#2


引用 1 楼 n7zj0x8 的回复:
flush不可能会让它不稳定的,这个你要绝对相信的.
 这里很有可能是你的线程不安全引起的,,Socket貌似不能跨线程使用的吧.

可能flush不是引起问题的真正原因,但是注释掉以后确实变得稳定了。我在使用socket时做了互斥,我们的框架设计是登陆和心跳一定要使用同一个socket。

#3


哎...我猜我肯定解释不清楚,如果你贴代码,到可以看下.
socket貌似只能工作在一个线程里面..你用两个线程,里终也是合并到一个线程工作.
还有就是如果你用Qt写代码的话,我可以很确定的说,你可能一辈子也用不到互斥锁了.Qt信号槽就可以保证线程安全

#4


引用 3 楼 n7zj0x8 的回复:
哎...我猜我肯定解释不清楚,如果你贴代码,到可以看下.
socket貌似只能工作在一个线程里面..你用两个线程,里终也是合并到一个线程工作.
还有就是如果你用Qt写代码的话,我可以很确定的说,你可能一辈子也用不到互斥锁了.Qt信号槽就可以保证线程安全

线程是用Windows的API创建的

QTcpSocket* g_tcpSocket = new QTcpSocket();
HANDLE g_handleHeartBeat = CreateThread(NULL, 0, RunHeartBeat, g_Client, 0, NULL); // 创建心跳线程
DWORD WINAPI RunHeartBeat(LPVOID param)
{
    WaitForSingleObject(g_hMutex, INFINITE);
    Request request; // 需要向服务端发送的内容
    //.....填写request
    int nleft, nbytes;
    char* ptr = (char*)&request;

    nleft = 12;  // 需要发送的长度
     
    for (; nleft  > 0; )
    {
        nbytes = g_tcpSocket->write(ptr, nleft);
        g_tcpSocket->flush();     // 注释掉这行以后release版本就稳定了,但是debug版本不会及时发出消息

        if (nbytes <= 0)
        {
                // .......
                 ReleaseMutex(g_hMutex);
                return -1;
        }
        nleft -= nbytes;
        ptr += nbytes;
    }
    ReleaseMutex(g_hMutex);
}

主线程基本是一样的代码。能帮忙看一下吗,多谢!

#5


引用 4 楼 YouNeverCanTell 的回复:
主线程基本是一样的代码。能帮忙看一下吗,多谢!

差点凌乱了..这混合编程用得....目测你的问题应该是混合编程引起的

我给你贴一个处理了write函数的QTcpSocket,这个socket被我移动到一个单独的线程里面去了,但它write函数是线程安全的.  如果你有什么其它的函数接口需要调用m_pQTcpSocket的,像我那样写一个信号一个槽,然后连接起来,间接调用...这样可以保证m_pQTcpSocket在一个线程里面被使用.
这里问题来了,你可能会觉得这样写很麻烦或者不习惯.这个没有办法.如果你要用windows线程或者编程思想,处理Qt
的东西,真的会很纠结.. 貌似QTcpSocket在不同的Qt线程里面,调用它会报错(QSocketNotifier: socket notifiers cannot be enabled from another thread)..这里你的为什么没有报错,我估计就是因为你是windows的线程原因..不知道我有没有说错. 
这里要么你使用windows的socket要么你使用Qt的线程..如果使用Qt的线程,又要说一堆...这个问题就真的复杂起来了....我只能帮你到这里了.


#ifndef MYTCPSOCKET_H
#define MYTCPSOCKET_H

#include <QTcpSocket>
#include <QThread>
#include <QDebug>
#include <QHostAddress>

class MyTcpSocket : public QThread
{
    Q_OBJECT
public:
    MyTcpSocket()
        : m_pQTcpSocket(new QTcpSocket())
    {
        this->start();
        this->moveToThread(this);
        m_pQTcpSocket->moveToThread(this);

        connect(this, SIGNAL(DoMyWrite(QByteArray)),
                this, SLOT(OnMyWrite(QByteArray)));
        connect(this, SIGNAL(DoMyConnect()),
                this, SLOT(OnMyConnectToHost()));
    }

    ~MyTcpSocket()
    {
        this->exit();
        this->wait(10 * 1000);
    }

    void myWrite(const char *data, qint64 len)
    {
        emit DoMyWrite(QByteArray(data, len));
    }

    void myConnectToHost()
    {
        emit DoMyConnect();
    }

signals:
    void DoMyWrite(const QByteArray &data);
    void DoMyConnect();

private slots:
    void OnMyWrite(const QByteArray &data)
    {
        qDebug() << "write" << QThread::currentThreadId();
        m_pQTcpSocket->write(data);
        m_pQTcpSocket->flush();
    }
    void OnMyConnectToHost()
    {
        qDebug() << "myConnect" << QThread::currentThreadId();
        m_pQTcpSocket->connectToHost(QHostAddress::LocalHost, 8811);
    }

private:
    QTcpSocket * const m_pQTcpSocket;
};

#endif // MYTCPSOCKET_H


#6


引用 5 楼 n7zj0x8 的回复:
Quote: 引用 4 楼 YouNeverCanTell 的回复:

主线程基本是一样的代码。能帮忙看一下吗,多谢!

差点凌乱了..这混合编程用得....目测你的问题应该是混合编程引起的

我给你贴一个处理了write函数的QTcpSocket,这个socket被我移动到一个单独的线程里面去了,但它write函数是线程安全的.  如果你有什么其它的函数接口需要调用m_pQTcpSocket的,像我那样写一个信号一个槽,然后连接起来,间接调用...这样可以保证m_pQTcpSocket在一个线程里面被使用.
这里问题来了,你可能会觉得这样写很麻烦或者不习惯.这个没有办法.如果你要用windows线程或者编程思想,处理Qt
的东西,真的会很纠结.. 貌似QTcpSocket在不同的Qt线程里面,调用它会报错(QSocketNotifier: socket notifiers cannot be enabled from another thread)..这里你的为什么没有报错,我估计就是因为你是windows的线程原因..不知道我有没有说错. 
这里要么你使用windows的socket要么你使用Qt的线程..如果使用Qt的线程,又要说一堆...这个问题就真的复杂起来了....我只能帮你到这里了.


#ifndef MYTCPSOCKET_H
#define MYTCPSOCKET_H

#include <QTcpSocket>
#include <QThread>
#include <QDebug>
#include <QHostAddress>

class MyTcpSocket : public QThread
{
    Q_OBJECT
public:
    MyTcpSocket()
        : m_pQTcpSocket(new QTcpSocket())
    {
        this->start();
        this->moveToThread(this);
        m_pQTcpSocket->moveToThread(this);

        connect(this, SIGNAL(DoMyWrite(QByteArray)),
                this, SLOT(OnMyWrite(QByteArray)));
        connect(this, SIGNAL(DoMyConnect()),
                this, SLOT(OnMyConnectToHost()));
    }

    ~MyTcpSocket()
    {
        this->exit();
        this->wait(10 * 1000);
    }

    void myWrite(const char *data, qint64 len)
    {
        emit DoMyWrite(QByteArray(data, len));
    }

    void myConnectToHost()
    {
        emit DoMyConnect();
    }

signals:
    void DoMyWrite(const QByteArray &data);
    void DoMyConnect();

private slots:
    void OnMyWrite(const QByteArray &data)
    {
        qDebug() << "write" << QThread::currentThreadId();
        m_pQTcpSocket->write(data);
        m_pQTcpSocket->flush();
    }
    void OnMyConnectToHost()
    {
        qDebug() << "myConnect" << QThread::currentThreadId();
        m_pQTcpSocket->connectToHost(QHostAddress::LocalHost, 8811);
    }

private:
    QTcpSocket * const m_pQTcpSocket;
};

#endif // MYTCPSOCKET_H



谢谢,改用定时器确实不会有这问题了。