I try to use QTcpSserver, which would keep connection with one and only one client at a time, until the client disconnects. So, I keep the client with a member pointer in my class.
The problem arises here: In the examples I see on the internet, after disconnected(), it is called deleteLater(). Good, but I would use this class-member pointer again for another connection. Remember that the server keeps one and only one client at a time. So, what if the socket object is deleted after another connection assigned on it?
What I mean is:
class TcpServer(QObject* o) : public QTcpServer {
...
private:
QTcpSocket* client;
}
void TcpServer::connected() {
client = this->nextPendingConnection();
this->pauseAccepting();
connect(client, SIGNAL(disconnected()), client, SLOT(clientDisconnected()));
}
void TcpServer::clientDisconnected() {
client->deleteLater();
this->resumeAccepting();
}
Scenario is this:
Client connected. So, client = nextPendingConnection();
Server paused listening. Does not accept new connection.
Client is disconnected. client needs to be released. So, client->deleteLater() is calleed.
Server continues listening.
New connection comes. So, I need to client = nextPendingConnection();
But, previous client object was deleted? Maybe? Maybe not? What if event loop tries to delete client, after I have assigned the new connection to it in step 5?
So, how would I keep one and only one client, while deleting previous disconnected ones?
Would it be safe if I do this?
void TcpServer::clientDisconnected()
{
QSocket* ptr = client;
ptr->deleteLater();
...
}
I will cite Qt documentation about it:
The object will be deleted when control returns to the event loop.
So deleteLater() is a delayed delete. The object is to be regarded as deleted as soon as the call deleteLater() was made.
Your nextPendingConnection() call will create another object that need to be deleted some time later.
However in your case you only allow one pending connection as you said and disallow accepting until client gets disconnected. I this case it should be safe, in other cases you could overwrite your client pointer and will lose control over it (memory leak).
Even in your case, I would prefer this solution:
void TcpServer::clientDisconnected()
{
if (qobject_cast<QAbstractSocket*>(sender())) {
sender()->deleteLater();
}
...
}
This would also be safe if more than one connection is allowed in future changes of your application.
As i understand nextPendingConnection(); will return pointer to new QTcpSocket class object so you have nothing to worry about.
deleteLater() will scheduled for deletion only your old object. QTcpSocket* client contains only pointer to QTcpSocket class object. When you calling deleteLater() Qt will delete only object to which client was pointed at time of calling this function.
Related
Disclaimer: I am relatively new to Qt and any type of programming that revolves around Threads and Networking. I have also adopted a lot of code from Qt Examples, API, and other online examples.
All code can be found on GitHub. This code is relatively as simple as it can get minus striping out GUI. I figure supplying it this way would help as well versus just pasting the code below.
I want to use and believe I need to use Threads as I need multiple clients send a request to the server, the server run some SQL code, then spit out the results back to the client (basically deriving a MySQL Server, but specific to what I am doing). Right now though, I am just working on learning the workings of it all.
With all that being said, as the Title states.. My client can connect to the server, the server sets up the thread, and will receive data (a String) through the readReady. After the data is read in, for right now I am just trying to echo it back to the client. It will do this, but only once. Then it spits out:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x266cca92ea0), parent's thread is serverThread(0x266cca9ed60), current thread is QThread(0x266cac772e0)
I cannot send any further data to the server unless I have the client reconnect, then after the data is sent, it will do its job but then spit out the same error and cease functioning. I have tried quite a bit of different things, but cannot seem to fix the issue. I even tried setting up a SIGNAL/SLOT for this as suggested in API:
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.
Anyway, any help would be greatly appreciated! My Code is below..
Server
ServerThread.cpp
// Project
#include "ServerDialog.h"
#include "ServerThread.h"
ServerThread::ServerThread(qintptr _socketDiscriptor, QObject *parent /*= 0*/)
: QThread(parent)
{
socketDiscriptor = _socketDiscriptor;
}
void ServerThread::run()
{
emit threadStarted(socketDiscriptor);
// Start Thread
clientSocket = new QTcpSocket;
// Set SocketDisc
if (!clientSocket->setSocketDescriptor(socketDiscriptor))
{
emit error(clientSocket->error());
return;
}
// Connect Socket and Signal
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
//// Loop Thread to Stay Alive for Signals and Slots
exec();
}
void ServerThread::readyRead()
{
QDataStream in(clientSocket);
in.setVersion(QDataStream::Qt_5_7);
in.startTransaction();
QString dataReceived;
in >> dataReceived;
if (!in.commitTransaction())
{
emit readyReadError(socketDiscriptor);
return;
}
emit readyReadMessage(socketDiscriptor, dataReceived);
echoData(dataReceived);
}
void ServerThread::disconnected()
{
emit threadStopped(socketDiscriptor);
clientSocket->disconnect();
clientSocket->deleteLater();
this->exit(0);
}
void ServerThread::echoData(QString &data)
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_7);
out << data;
clientSocket->write(block);
}
So in ServerThread.cpp when echoData is called, that is when the error shows up and the Socket ceases functioning.
Any and all help will be appreciated. I know there are a few other posts regarding "Cannot create children for..." in regards to Threads. But I did not find any of them helpful. The one thing that I did find interesting but did not understand was maybe using moveToThread() but a lot of mixed comments on that.
I learn best through code examples along with explanation versus just an explanation or pointer to API. Thank you!
Most of Qt network functions are asynchronous; they do not block the calling thread. There is no need to mess up with threads if you are using QTcpSockets. In fact, creating a thread for every socket is an overkill, since that thread will spend most of its time just waiting for some network operation to finish. Here is how I would implement a single-threaded echo server in Qt:
#include <QtNetwork>
#include <QtCore>
//separate class for the protocol's implementation
class EchoSocket : public QTcpSocket{
Q_OBJECT
public:
explicit EchoSocket(QObject* parent=nullptr):QTcpSocket(parent){
connect(this, &EchoSocket::readyRead, this, &EchoSocket::EchoBack);
connect(this, &EchoSocket::disconnected, this, &EchoSocket::deleteLater);
}
~EchoSocket() = default;
Q_SLOT void EchoBack(){
QByteArray receivedByteArray= readAll();
write(receivedByteArray);
disconnectFromHost();
}
};
class EchoServer : public QTcpServer{
public:
explicit EchoServer(QObject* parent= nullptr):QTcpServer(parent){}
~EchoServer() = default;
//override incomingConnection() and nextPendingConnection()
//to make them deal with EchoSockets instead of QTcpSockets
void incomingConnection(qintptr socketDescriptor){
EchoSocket* socket= new EchoSocket(this);
socket->setSocketDescriptor(socketDescriptor);
addPendingConnection(qobject_cast<QTcpSocket*>(socket));
}
EchoSocket* nextPendingConnection(){
QTcpSocket* ts= QTcpServer::nextPendingConnection();
return qobject_cast<EchoSocket*>(ts);
}
};
int main(int argc, char* argv[]){
QCoreApplication a(argc, argv);
EchoServer echoServer;
echoServer.listen(QHostAddress::Any, 9999);
QObject::connect(&echoServer, &EchoServer::newConnection, [&](){
EchoSocket* socket= echoServer.nextPendingConnection();
qDebug() << "Got new connection from: " << socket->peerAddress().toString();
});
return a.exec();
}
#include "main.moc"
Notes:
This server has the ability to handle more than one client at the same time, since there is no blocking. The thread will just respond to the event that happens with the appropriate action; So, if that event was a new connection, it will create a new EchoSocket object to handle it and prints a statement out to qDebug(), and if that event was receiving something on a previously created socket, the same thread will echo received data back and close the connection. It will never block on a single connection waiting for data to arrive nor it will block waiting for a new connection to arrive.
Since you mention using some SQL queries in response for some connections later in your project. Please avoid threading since an SQL database connection in Qt can be used only from the thread that created it, see docs here. So, You'll have to either create a new database connection for each thread (and thus for each connection) in your application (and this is beyond just overkill), or switch later to a single threaded design.
In this section, I am explaining why threading does not work for you the way you are doing it:
You should not be declaring slots in your QThread subclass, Instead, use worker QObjects and move them to QThreads as needed.
The quote you have provided in your question is the exact explanation for why you get this warning. The ServerThread instance you create will be living in the main thread (or whatever thread that created it). Now let's consider this line from your code:
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
The signal readyRead() will be emitted from the current ServerThread instance (since the clientSocket object that emits it lives there), However, the receiver object is the current ServerThread instance, But that lives in the main thread. Here is what the documentation says:
If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.
Now, the main point of Qt::QueuedConnection is executing the slot in the receiver object's thread. This means that, your slots ServerThread::readyRead() and ServerThread::disconnected will get executed in the main thread. This is most likely not what you meant to do, since you'll end up accessing clientSocket from the main thread. After that, any call on clientSocket that results in child QObjects being created will result in the warning you get (you can see that QTcpSocket::write() does this here).
Mixed comments of movetothread are linked mostly to usage of it to move thread object to itself.
The quote hints that the members of QThread aren't designed to be called from worker. Strictly proper way to call signal would be by using worker object model, that was shown in Qt examples and explained a few times on QT-related blogs:
class Worker : public QObject
{
Q_OBJECT
private slots:
void onTimeout()
{
qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
}
};
class Thread : public QThread
{
Q_OBJECT
private:
void run()
{
qDebug()<<"From work thread: "<<currentThreadId();
QTimer timer;
Worker worker;
connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
timer.start(1000);
exec();
}
};
worker constructed inside run() is "property" of the thread it created, so figuratively speaking, it is slaved to its context. The same effect maybe achieved if you create worker in other thread, then move it to this thread before connection was made. When you connect signal to slot of the QThread itself, you connect child thread to thread it was created by.
Use of
connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()), Qt::DirectConnection);
or creating connection from your thread sometimes seems to achieve proper result, but not in this case, where you try use objects constructed in different threads together. Calling moveToThread(this) in constructor is a thing not recommended to do.
So i just programmed a simple multithreaded client server application using winsock2 and TCP.
Here is a quick summary of how it works:
The servers main-thread is in a endless loop accepting clients and then also adding them to the servers vector which holds every connected client like this:
(only adding in the important stuff for my question)
std::vector <Client*> clients;
while (true){
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
}
When a new client connects to the server we basically create a new Client object with the socket of the new client and the server itself as parameters.
My idea was then to give every client its own thread so every client can send data at the same time.
std::thread tickThread;
Client::Client(SOCKET socket,Server* server) :
isConnected(true),
socket(socket),
server(server)
{
tickThread = std::thread(&Client::tick,this);
}
The thread for the client then checks if the client sent something and then sends it to the server. It also checks wether the client is still connected.
void Client::tick(){
while (isConnected){
errorHandler = recv(socket, receivedData, 255, 0);
if (errorHandler == SOCKET_ERROR){
disconnect();
}
else {
//send received data to server
}
}
If the client disconnected it tells the server to remove the client from the connected clients vector and then sets the "isConnected" bool to false so the thread can exit its function.
void Client::disconnect(){
isConnected = false;
server->removeClient(this);
}
This is how it's supposed to work, however as soon as a client disconnects again the server crashes with the error:
R6010 - abort() has been called
All debugging shows me is this as my error:
switch (_CrtDbgReportW(_CRT_ERROR, NULL, 0, NULL, L"%s", error_text)){
case 1: _CrtDbgBreak(); msgshown = 1; break;
case 0: msgshown = 1; break;
}
So yeah i don't really know whats causing this crash, however i suspect that it might be related to the thread using a function of the client that's basically being deleted as it is being removed from the client vector of the server.
And if this turns out to be the problem could you guys give me ideas for a better way of implementing every client having its own thread?
Edit: changed the vector error, however the crash still happens as soon as a client disconnects
The error is in this block of code:
while (true){
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
}
Client(accept(serverSocket, NULL, NULL), this) is an expression which generates a temporary Client object that is destroyed when the statement finishes executing. However, you take the address of that temporary object and add it to your vector.
If you want to create Client objects and store pointers to them, you will need to allocate memory for them. I would recommend using std::unique_ptr to manage them so that your vector claims ownership of their memory and automatically frees them if they are removed from the vector or the vector itself is destroyed. Then your code becomes:
std::vector<std::unique_ptr<Client>> clients;
while (true){
clients.push_back(std::make_unique<Client>(accept(serverSocket, NULL, NULL), this));
}
In this piece of code:
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
You are pushing an address of a temporary object into the container. When push_back() is done, the temporary object is destroyed, so that address is no longer valid. I wonder, what kind of compiler allows you to do this.
I'm programming an application that uses QUdpSockets.
As I'm getting memory problems due to creating sockets with the operator new I would like to know if it is necesary to delete them after closing it.
Code below:
socket = new QUdpSocket(this);
socket->bind();
connect(socket, SIGNAL(readyRead()), this, SLOT(getResponse()));
socket->close();
delete socket; //Do I have to do this to free the mem?
Help will be thanked.
Depends on what this is. Whenever that gets destroyed, the QUdpSocket will be too.
As soon as you don't need the socket anymore you can call :
socket->deleteLater();
And yes, it's better to destroy the socket when you don't need it anymore.
An other solution is to delete 'this', so socket will be also deleted.
If your done with the socket you should delete it. This way you are on the safe side. Also it doesnt hurt. However as it was already pointed out "this" will take for the destruction of the socket (see http://doc.qt.io/qt-4.8/qobject.html#QObject ).
I'm writing a tcp based server using Qt.
I plan this server to be multithreaded,
so my tcpserver class inherits from QTcpServer and overrides incomingConnection(). Everything is fine, except when it comes to deleting a user.
The TcpServer class manages
a list of QSharedPointer<Client>. When I remove the said client from the list, it gets automatically deleted because of the smart pointer.
My Client class owns a QSharedPointer<QTcpSocket> which means that the client's
QTcpSocket gets deleted when the client is deleted.
Problem is, it seems that Qt tries to use this socket after its deletion, causing Segmentation Fault.
Should I manages a list for the sockets only, and call deleteLater() on them when I dont need them anymore?
Or should I switch my socket's pointer in client class to a normal pointer?
void SlotSocketError(void)
{
QTcpSocket sock = qobject_cast<QTcpSocket *>(QObject::sender());
QSharedPointer<Client> client = GetClientFromSocket(sock);
_clientList.removeAt(GetClientPositionInList(client));
}
QList<QSharedPointer<Client> > _clientsList; // From TcpServer header.
/* Client's class header */
QSharedPointer<QTcpSocket> _socket;
You need to use deleteLater on the Object. Incoming messages may come in after you delete the QTCPSocket. It is documented in Assistant. You can find an example here: qthelp://com.trolltech.qt.472/qdoc/qt4-network.html
M
When you create your QSharedPointers you can pass a deleter to them, so that they'll use deleteLater instead of delete when you remove them from the list.
There is an example that does exactly that in the documentation too:
http://doc.trolltech.com/latest/qsharedpointer.html#QSharedPointer-3
I've modified the threaded fortune-server from Qt examples.
The client connects to the server and then sends a header to authenticate.
tcpSocket = new QTcpSocket();
tcpSocket->connectToHost(addr, port);
QByteArray block = "someheader";
int x = tcpSocket->write(block);
qDebug() << x;
The client seems OK here and qDebug prints the actual size of block.
On the server side I've predefined incomingConnection and I start thread to each new connection.
void Server::incomingConnection(int socketDescriptor) {
const QString &str = vec[qrand() % vec.size()];
SpellThread *thread = new SpellThread(socketDescriptor, str);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
qDebug() << " -- incoming connection";
thread->start();
}
I'm connecting sock to check is there something to read. (sock here is QTcpServer*)
void SpellThread::run() {
qDebug() << " -- in spellthread";
connect(sock, SIGNAL(readyRead()), this, SLOT(checkBytes()));
//....
qDebug() << " -- end spellthread";
}
The first problem is that when I'm sending data from the client, readyRead is not fired. (I've added debug message in checkBytes)
Messages are:
-- incoming connection
-- in spellthread
-- end spellthread
Although the client prints the actual size of header length.
The second problem is that checkBytes currently is very bad-designed. First it checks is header OK and sets a flag, then it gets the size of message and sets another flag and finally it gets the real message. This is very clumsy. I first tried to escape signals and instead use sock->waitForReadyRead(). However it always returns false. (From the docs: "Reimplement this function to provide a blocking API for a custom device. The default implementation does nothing, and returns false.").
So how to really make a client/server application in Qt with multiple clients and multiple reads/writes? I really want suggestions to improve design of my application and to solve my current two problems.
You can't use slots or socket signals with a thread without calling QThread::exec() to start an event loop within that thread/the run function.
Since your checkBytes slot belongs to QThread, it wouldn't be executed by the thread (there is a detailed article about QThreads here)
The closest example that seems to already do what you want is the Network Chat (particularly the two classes Server and Connection).
----------Edit
If you need to use threads (without any slot), the QTcpSocket object must belongs to the same thread as the one where you call waitForReadyRead. For example, with:
SpellThread::SpellThread(int socketDescriptor, const QString & str) {
tcpSocket = new QTcpSocket(); // There should be no parent to be able
// to move it to the thread
tcpSocket->moveToThread(this);
...
Or by creating the QTcpSocket object inside the run function so that it automatically belongs to that thread (it was briefly explained in the fortune example).
If you allocate the QTcpSocket dynamically, and because it won't have a parent, you should also delete it manually.