QTcpSocket 在工作进程中连续写入。避免内存泄漏的最佳实践
QTcpSocket continuous write in worker process. Best practice to avoid memory leaks
我必须在特定的时间间隔内通过 TCP 套接字向服务器发送一个小数据包。我正在用 Qt 开发。
我的想法是创建继承自 QObject 的 class,将 Socket 写入部分放入这样的 class 中的无限循环中,并将其作为单独的线程执行。
它可以工作,但会泄漏内存....在这一点上我很迷茫。
这是我到目前为止所做的(某种伪代码...):
Task_SendPacket.h
#ifndef TASK_SENDPACKET_H
#define TASK_SENDPACKET_H
#include <QObject>
#include <QTcpSocket>
class Task_SendPacket : public QObject
{
Q_OBJECT
public:
explicit Task_SendPacket(QObject *parent = nullptr);
public slots:
void startTask();
void _connected();
void _readReady();
void _error(QAbstractSocket::SocketError _Error);
signals:
private:
QTcpSocket *mpSocket;
char SomeData[100];
};
#endif // TASK_SENDPACKET_H
Task_SendPacket.cpp
#include "Task_SendPacket.h"
#include <QThread>
#include <QDebug>
Task_SendPacket::Task_SendPacket(QObject *parent)
: QObject(parent)
{
}
void Task_SendPacket::startTask(){
while(true){
mpSocket = new QTcpSocket(this);
connect(mpSocket, &QTcpSocket::disconnected, mpSocket, &QTcpSocket::deleteLater);
connect(mpSocket, &QTcpSocket::connected, this, &Task_SetSelectedCamera::_connected);
connect(mpSocket, &QTcpSocket::readyRead, this, &Task_SetSelectedCamera::_readReady);
connect(mpSocket, &QTcpSocket::errorOccurred,this, &Task_SetSelectedCamera::_error);
mpSocket->connectToHost("192.168.0.1", 50100, QTcpSocket::ReadWrite);
if(!mpSocket->waitForConnected(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - Connection timeout";
}
if(!mpSocket->waitForBytesWritten(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - write timeout";
mpSocket->disconnectFromHost();
}
if(!mpSocket->waitForReadyRead(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - read timeout";
mpSocket->disconnectFromHost();
}
QThread::msleep(1000);
}
void Task_SetSelectedCamera::_connected(){
if(mpSocket->write(SomeData, 100) == -1){
qWarning() << "Write Header error ";
};
}
void Task_SetSelectedCamera::_readReady(){
char DataRead[100] = mpSocket->readAll();
/* Do stuff with DataRead...*/
mpSocket->disconnectFromHost();
}
void Task_SetSelectedCamera::_error(QAbstractSocket::SocketError _Error){
qWarning() << _Error;
}
}
main.cpp
/* Start Task SetSelectedCamera */
QThread *ServiceThread1 = new QThread();
Task_SendPacket *oTaskSendPacket = new Task_SendPacket();
oTaskSendPacket->moveToThread(ServiceThread1);
QObject::connect(ServiceThread1, &QThread::finished, oTaskSendPacket, &QObject::deleteLater);
QObject::connect(ServiceThread1, &QThread::started, oTaskSendPacket, &Task_SendPacket::startTask);
ServiceThread1->start();
qInfo() << "Task SendPacket started";
如果我让应用程序 运行 运行几天,它会增加内存并崩溃。
这是创建新 QTcpSocket、连接它并发送数据的正确方法吗?
萨克斯
编辑
我已经编辑了原来的 post 因为我没有关注正确的点。在我的想法中, new QTcpSocket(...) 必须在 while 循环的每次迭代中 运行 因为我希望 mpSocket 每次断开连接时都被标记为删除。
在第二个实验中(在下面报告)我试图在 while 循环之前移动套接字部分......它仍然有效。
mpSocket = new QTcpSocket(this);
connect(mpSocket, &QTcpSocket::disconnected, mpSocket, &QTcpSocket::deleteLater);
connect(mpSocket, &QTcpSocket::connected, this, &Task_SetSelectedCamera::_connected);
connect(mpSocket, &QTcpSocket::readyRead, this, &Task_SetSelectedCamera::_readReady);
connect(mpSocket, &QTcpSocket::errorOccurred,this, &Task_SetSelectedCamera::_error);
while(true){
mpSocket->connectToHost("192.168.0.1", 50100, QTcpSocket::ReadWrite);
if(!mpSocket->waitForConnected(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - Connection timeout";
}
if(!mpSocket->waitForBytesWritten(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - write timeout";
mpSocket->disconnectFromHost();
}
if(!mpSocket->waitForReadyRead(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - read timeout";
mpSocket->disconnectFromHost();
}
QThread::msleep(1000);
}
所以现在的问题是:
- 每次迭代都创建一个新的 QTcpSocket 是否正确?
- 为什么断开连接后套接字仍然有效(因为我这样做了
收到断开连接...我跟踪了)
真丢脸!
我在很多方面都错了,但请原谅我,我年轻又花哨。
我想 post 在这里谈谈我犯过的错误,希望它能帮助其他人,因为我认为我已经得到了这个错误的解决方案,这是受我以前使用 RTOS 编程的性经验的影响。
首发
永远不要在 QThread 或 QObject 中放置无限 while 循环,即 moveToThread(...) 到 QThread。这是因为 while 循环将使 QEventLoop 与 运行 保持一致。一切都会卡在里面
while(true){
...
}
和none应用程序的生命周期(包括信号和槽)将继续!
然后 - Signal/Slot卡住
如果没有
...
if(!mpSocket->waitForBytesWritten(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - write timeout";
mpSocket->disconnectFromHost();
}
if(!mpSocket->waitForReadyRead(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - read timeout";
mpSocket->disconnectFromHost();
}
...
没有ReadyRead信号,没有BytesWritten信号等等。这是(显然......现在)因为这些函数正在阻塞并且因为我的无限循环正在阻塞 signal/slot 逻辑所以没有其他方法可以让我的 QTcpSocket 工作。如果应用程序生命周期正常运行,则信号和插槽会正常运行,否则......它们不会。
最后 - deleteAater() 不工作
我无法理解的最后一件事是为什么,把我的
mpSocket = new QTcpSocket(this);
在 while 循环之前(应该在每次迭代时删除套接字,套接字仍然可以工作。
这也是因为如果 QEventLoop 不工作,套接字的 deleteLater() 将不工作......顺便说一句,这也是(我认为)我的应用程序泄漏内存的原因!
现在我已经用 QTimer 逻辑重新实现并且它工作正常。
我认为我被骗的原因是因为来自 RTOS 的基本思想是在每个线程中都有一个初始化部分和一个循环部分。这就是我寻找无限循环的原因...
仍然怀疑我如何在没有以下条件的情况下在 QThread 中进行无限循环:
- 打乱应用程序逻辑
- 使用 QTimer
谢谢
我必须在特定的时间间隔内通过 TCP 套接字向服务器发送一个小数据包。我正在用 Qt 开发。
我的想法是创建继承自 QObject 的 class,将 Socket 写入部分放入这样的 class 中的无限循环中,并将其作为单独的线程执行。
它可以工作,但会泄漏内存....在这一点上我很迷茫。
这是我到目前为止所做的(某种伪代码...):
Task_SendPacket.h
#ifndef TASK_SENDPACKET_H
#define TASK_SENDPACKET_H
#include <QObject>
#include <QTcpSocket>
class Task_SendPacket : public QObject
{
Q_OBJECT
public:
explicit Task_SendPacket(QObject *parent = nullptr);
public slots:
void startTask();
void _connected();
void _readReady();
void _error(QAbstractSocket::SocketError _Error);
signals:
private:
QTcpSocket *mpSocket;
char SomeData[100];
};
#endif // TASK_SENDPACKET_H
Task_SendPacket.cpp
#include "Task_SendPacket.h"
#include <QThread>
#include <QDebug>
Task_SendPacket::Task_SendPacket(QObject *parent)
: QObject(parent)
{
}
void Task_SendPacket::startTask(){
while(true){
mpSocket = new QTcpSocket(this);
connect(mpSocket, &QTcpSocket::disconnected, mpSocket, &QTcpSocket::deleteLater);
connect(mpSocket, &QTcpSocket::connected, this, &Task_SetSelectedCamera::_connected);
connect(mpSocket, &QTcpSocket::readyRead, this, &Task_SetSelectedCamera::_readReady);
connect(mpSocket, &QTcpSocket::errorOccurred,this, &Task_SetSelectedCamera::_error);
mpSocket->connectToHost("192.168.0.1", 50100, QTcpSocket::ReadWrite);
if(!mpSocket->waitForConnected(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - Connection timeout";
}
if(!mpSocket->waitForBytesWritten(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - write timeout";
mpSocket->disconnectFromHost();
}
if(!mpSocket->waitForReadyRead(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - read timeout";
mpSocket->disconnectFromHost();
}
QThread::msleep(1000);
}
void Task_SetSelectedCamera::_connected(){
if(mpSocket->write(SomeData, 100) == -1){
qWarning() << "Write Header error ";
};
}
void Task_SetSelectedCamera::_readReady(){
char DataRead[100] = mpSocket->readAll();
/* Do stuff with DataRead...*/
mpSocket->disconnectFromHost();
}
void Task_SetSelectedCamera::_error(QAbstractSocket::SocketError _Error){
qWarning() << _Error;
}
}
main.cpp
/* Start Task SetSelectedCamera */
QThread *ServiceThread1 = new QThread();
Task_SendPacket *oTaskSendPacket = new Task_SendPacket();
oTaskSendPacket->moveToThread(ServiceThread1);
QObject::connect(ServiceThread1, &QThread::finished, oTaskSendPacket, &QObject::deleteLater);
QObject::connect(ServiceThread1, &QThread::started, oTaskSendPacket, &Task_SendPacket::startTask);
ServiceThread1->start();
qInfo() << "Task SendPacket started";
如果我让应用程序 运行 运行几天,它会增加内存并崩溃。
这是创建新 QTcpSocket、连接它并发送数据的正确方法吗?
萨克斯
编辑
我已经编辑了原来的 post 因为我没有关注正确的点。在我的想法中, new QTcpSocket(...) 必须在 while 循环的每次迭代中 运行 因为我希望 mpSocket 每次断开连接时都被标记为删除。
在第二个实验中(在下面报告)我试图在 while 循环之前移动套接字部分......它仍然有效。
mpSocket = new QTcpSocket(this);
connect(mpSocket, &QTcpSocket::disconnected, mpSocket, &QTcpSocket::deleteLater);
connect(mpSocket, &QTcpSocket::connected, this, &Task_SetSelectedCamera::_connected);
connect(mpSocket, &QTcpSocket::readyRead, this, &Task_SetSelectedCamera::_readReady);
connect(mpSocket, &QTcpSocket::errorOccurred,this, &Task_SetSelectedCamera::_error);
while(true){
mpSocket->connectToHost("192.168.0.1", 50100, QTcpSocket::ReadWrite);
if(!mpSocket->waitForConnected(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - Connection timeout";
}
if(!mpSocket->waitForBytesWritten(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - write timeout";
mpSocket->disconnectFromHost();
}
if(!mpSocket->waitForReadyRead(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - read timeout";
mpSocket->disconnectFromHost();
}
QThread::msleep(1000);
}
所以现在的问题是:
- 每次迭代都创建一个新的 QTcpSocket 是否正确?
- 为什么断开连接后套接字仍然有效(因为我这样做了 收到断开连接...我跟踪了)
真丢脸!
我在很多方面都错了,但请原谅我,我年轻又花哨。
我想 post 在这里谈谈我犯过的错误,希望它能帮助其他人,因为我认为我已经得到了这个错误的解决方案,这是受我以前使用 RTOS 编程的性经验的影响。
首发
永远不要在 QThread 或 QObject 中放置无限 while 循环,即 moveToThread(...) 到 QThread。这是因为 while 循环将使 QEventLoop 与 运行 保持一致。一切都会卡在里面
while(true){
...
}
和none应用程序的生命周期(包括信号和槽)将继续!
然后 - Signal/Slot卡住
如果没有
...
if(!mpSocket->waitForBytesWritten(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - write timeout";
mpSocket->disconnectFromHost();
}
if(!mpSocket->waitForReadyRead(Protocol::NetworkTimeout_ms)){
qWarning() << "SS Packet send - read timeout";
mpSocket->disconnectFromHost();
}
...
没有ReadyRead信号,没有BytesWritten信号等等。这是(显然......现在)因为这些函数正在阻塞并且因为我的无限循环正在阻塞 signal/slot 逻辑所以没有其他方法可以让我的 QTcpSocket 工作。如果应用程序生命周期正常运行,则信号和插槽会正常运行,否则......它们不会。
最后 - deleteAater() 不工作
我无法理解的最后一件事是为什么,把我的
mpSocket = new QTcpSocket(this);
在 while 循环之前(应该在每次迭代时删除套接字,套接字仍然可以工作。
这也是因为如果 QEventLoop 不工作,套接字的 deleteLater() 将不工作......顺便说一句,这也是(我认为)我的应用程序泄漏内存的原因!
现在我已经用 QTimer 逻辑重新实现并且它工作正常。
我认为我被骗的原因是因为来自 RTOS 的基本思想是在每个线程中都有一个初始化部分和一个循环部分。这就是我寻找无限循环的原因...
仍然怀疑我如何在没有以下条件的情况下在 QThread 中进行无限循环:
- 打乱应用程序逻辑
- 使用 QTimer
谢谢