背景
对不起,这是一个如此复杂的问题,但它让我疯了。寻找解决方案可以帮助需要划分区域的应用程序。
我有一个非常划分的Qt程序,因为它旨在托管插件并在各种情况下使用,有时作为服务器,有时作为客户端,有时作为两者。加载的插件依赖于登录。 (因为为用户定义的访问不一定取决于用户,并且用户对数据和功能的访问可能是有限的)。
应用程序依赖于主exe,客户端,服务器和所有插件dll使用的核心DLL库(特定于应用程序)。客户端和服务器功能也在不同的dll中。我是这种编程风格的新手,因此可能导致我的问题。
我的问题:
我有一个名为“ BidirectionalTcpConnection ”的类,它在核心DLL中定义,可由可执行文件,客户端DLL和服务器dll使用。它是一个跟踪通过QTcpSocket来回传递的数据的类。我写这个类是为了避免我现在遇到的同样问题,除了在当前情况下使用QTcpSocket.ReadAll()函数时最初发生的问题。 (如果我尝试读取除最后一个字节之外的所有字节,然后使用QTcpSocket.peek(...)函数读取最后一个字节,它将正常工作。)
我的新类成功读取并写入套接字而没有错误但是当我尝试关闭或中止套接字时(这也发生在我早期的解决方法中......),我得到了同样的错误,当我尝试时读它(仅在最后一个字节)。 我收到一个为RtlValidateHeap指定的无效地址。 基本上它会在dbgheap.c中抛出“用户断点”
我的假设(我认为是错的):
dbgheap.c文件正在检查地址是否有效以及它是否驻留在当前堆上。
可能需要划分我的应用程序可能会导致此问题。提供给套接字以供发送的数据最初与 BidirectionalTcpConnection 的实例一起分配在可执行文件的堆中。 (我正在尝试发送登录并获得应用程序访问权限)。然而,套接字本身正在核心堆中分配(假设dll与内部数据的exe具有单独的堆)。我尝试通过对核心DLL代码中的套接字发送的每个数据进行深层复制来避免这种情况。但这还没有解决问题。可能是因为 BidirectionalTcpConnection 仍然在与套接字本身分开的堆上进行分配。
我可以帮助任何人的问题:
如果你们需要一些代码......我提供了我认为必要的东西。我可以根据要求提供更多。
部分代码:
对于初学者..这里有一些基本代码来显示事物的分配方式。在显示主界面之前,在main中执行登录。 w 是主界面窗口类实例。以下是启动导致崩溃的过程的代码:
while (loginFailed)
{
splash->showLogin();
while (splash->isWaitingOnLogin())
a.processEvents();
QString username(*splash->getUserName());
QString password(*splash->getPassword());
// LATER: encrypt login for sending
loginFailed = w.loginFailed(username, password, a);
}
以下是在可执行文件堆栈上实例化 BidirectionalTcpConnection 的代码并发送登录数据。此代码位于Qt主窗口类的几个单独的私有方法中。
// method A
// processes Qstring parameters into sendable data...
// then calls method B
// which creates the instance of *BidirectionalTcpConnection*
...
if (getServerAddress() == QString("LOCAL"))
mTcpConnection = new BidirectionalTcpConnection(getHostAddressIn()->toString(),
(quint16)ServerPorts::loginRequest, (long)15, this);
else
mTcpConnection = new BidirectionalTcpConnection(*getServerAddress(),
(quint16)ServerPorts::loginRequest, (long)15, this);
...
// back to method A...
mTcpConnection->sendBinaryData(*dataStream);
mTcpConnection->flushMessages(); // sends the data across the socket
...
// waits for response and then parses user data when it comes
while (waitForResponse)
{
if (mTcpConnection->hasBufferedMessages())
{
QString* loginXML = loginConnection->getNextMessageAsText();
// parse the xml
if (parseLogin(*loginXML))
{
waitForResponse = false;
}
...
}
}
...
// calls method that closes the socket which causes crash
mTcpConnection->abortConnection(); // crash occurs inside this method
delete mTcpConnection;
mTcpConnection = NULL;
以下是使用顺序的相关BidirectionalTcpConnection代码。 请注意,此代码位于核心dll中,因此可能是在单独的堆栈上分配数据...
BidirectionalTcpConnection::BidirectionalTcpConnection(const QString& destination,
quint16 port, long timeOutInterval, TimeUnit unit, QObject* parent) :
QObject(parent),
mSocket(parent),
...
{ }
void BidirectionalTcpConnection::sendBinaryData(QByteArray& data)
{
// notice I try and avoid different heaps where I can by copying the data...
mOutgoingMessageQueue.enqueue(new QByteArray(data)); // member is of QQueue type
}
QString* BidirectionalTcpConnection::getNextMessageAsText()
// NOTE: somehow I need to delete the returned pointer to prevent memory leak
{
if (mIncomingMessageQueue.size() == 0)
return NULL;
else
{
QByteArray* data = mIncomingMessageQueue.dequeue();
QString* stringData = new QString(*data);
delete data;
return stringData;
}
}
void BidirectionalTcpConnection::abortConnection()
{
mSocket.abort(); // **THIS CAUSES ERROR/CRASH**
clearQueues();
mIsConnected = false;
}