[SOLVED] Segmentation fault while trying to destroy QTcpSocket (and problem with signal/slot communication)
-
Hi,
I'm a beginner programmer and I wrote simple IM server. I have a problem with this code:
listener.cpp (shortened)
@
Listener::Listener(QObject* parent):
QTcpServer(parent)
{
}void Listener::incomingConnection(int handle){
std::cout<<"Incoming connection"<<std::endl;
QtConcurrent::run(this, &Listener::login, handle);
}void Listener::login(int handle){
TcpSocket socket; socket.setSocketDescriptor(handle); /*
... some login procedure ...
*/std::cout<<"Authentication successful"<<std::endl; QObject::connect(&socket,SIGNAL(newMsg(QString,QString)),router,SLOT(newMsgSlot(QString,QString)),Qt::DirectConnection);
QObject::connect(router,SIGNAL(newMsg(QString,QString)),&socket,SLOT(newMsgSlot(QString,QString)),Qt::DirectConnection);
QObject::connect(router,SIGNAL(pingReply(QString)),&socket,SLOT(pingReplySlot(QString)),Qt::DirectConnection);SharedData::clientByIDSem->acquire(); //checking if client with this ID is currently logged in if(SharedData::clientByID.find(id) != SharedData::clientByID.end()){ //if is, remove from list and disconnect with proper message SharedData::clientByID.remove(id); router->toMultipleLoginDC(id); } //adding to list socket.setID(id); QObject::connect(router,SIGNAL(multipleLoginDC(QString)),&socket,SLOT(multipleLoginDCSlot(QString)),Qt::DirectConnection); socket.setMsgMode(true); SharedData::clientByID.insert(id,Client(id,clientType)); clientStream<<QString(LOGIN_SUCCESSFUL); socket.flush(); SharedData::clientByIDSem->release(); emit restoreMsg(id); std::cout<<"User added successfully"<<std::endl; //client connected and communicating socket.waitForDisconnected(-1); //checking if client was disconnected by multipleLoginDC signal if(!socket.isMLDC()){ //if not, remove client from list SharedData::clientByIDSem->acquire(); SharedData::clientByID.remove(id); SharedData::clientByIDSem->release(); } //decrement number of currently connected clients SharedData::clientNumSem->acquire(); SharedData::clientNum--; SharedData::clientNumSem->release(); std::cout<<"User logged out"<<std::endl;
}
@router.cpp (shortened)
@
Router::Router(QObject *parent) :
QObject(parent)
{
}void Router::toMultipleLoginDC(QString ID){
emit multipleLoginDC(ID);
}
@tcpsocket.cpp (shortened)
@
TcpSocket::TcpSocket(QObject *parent) :
QTcpSocket(parent)
{
this->ID = QString();
this->access = new QSemaphore(1);
this->mldc = false;
}void TcpSocket::readyReadSlot(){
QDataStream stream(this);
this->access->acquire();
while(bytesAvailable()){
QString data;
stream>>data;
emit newMsg(ID,data);
}
this->access->release();
}void TcpSocket::multipleLoginDCSlot(QString ID){
if(this->ID == ID){
this->access->acquire();
std::cout<<"Disconnecting user "<<this->ID.toStdString()<<": multiple login"<<std::endl;
this->setID(QString());
QDataStream stream(this);
this->mldc = true;
stream<<QString(LOGGED_IN_FROM_ANOTHER_LOCATION);
flush();
this->access->release();}
}
void TcpSocket::pingReplySlot(QString ID){
std::cout<<"Ping reply"<<std::endl;
if(this->ID == ID){
this->access->acquire();
QDataStream stream(this);
stream<<QString(PING_REQ);
flush();
this->access->release();
}}
void TcpSocket::newMsgSlot(QString ID, QString data){
std::cout<<"New msg"<<std::endl;
if(this->ID == ID){
this->access->acquire();
QDataStream stream(this);
stream<<QString(data);
flush();
this->access->release();
}
}bool TcpSocket::isMLDC(){
return this->mldc;
}
@If there's new client trying to log in with ID which owner is currently logged in, the old client should be disconnected and then new client should be connected. Client after receiving LOGGED_IN_FROM_ANOTHER_LOCATION message disconnects from host. The server doesn't handle it properly and I think the problem is caused by signals. Anyway, I don't have an idea how to get rid of that.
With one (or more clients) it looks like this:
"One client"http://bronexproduction.pl/shared/frm/one_client.png
And now disconnect:
"One client with DC"http://bronexproduction.pl/shared/frm/one_client_dc.png
Everything's fine. When it comes to swap clients with the same ID the situation is a bit different:
"Disconnect with segmentation fault"http://bronexproduction.pl/shared/frm/DC.png
Probably when the signals emitted to TcpSocket objects makes TcpSocket methods running when the same TcpSocket object are being destroyed. It may cause the segmentation fault.
And when I put disconnectFromHost() here
@
void TcpSocket::multipleLoginDCSlot(QString ID){
if(this->ID == ID){
this->access->acquire();
std::cout<<"Disconnecting user "<<this->ID.toStdString()<<": multiplelogin"<<std::endl;
this->setID(QString());
QDataStream stream(this);
this->mldc = true;
stream<<QString(LOGGED_IN_FROM_ANOTHER_LOCATION);
flush();disconnectFromHost(); this->access->release(); }
}
@It started to look like this:
"No disconect"http://bronexproduction.pl/shared/frm/noDC.png
If it is caused by TcpSocket slots (and Router signals) this problem could also concern a situation when client is receiving message (TcpSocket::newMsg(QString,QString)) and trying to disconnect at the same time.
Maybe is there any way to prevent this methods from being invoked when program is about to delete them?
-
What are you doing with these lines?
@if(SharedData::clientByID.find(id) != SharedData::clientByID.end()){
//if is, remove from list and disconnect with proper message
SharedData::clientByID.remove(id); // <--- here 1.
router->toMultipleLoginDC(id); //<--- here 2.
}@and here 3.:
@
QObject::connect(router,SIGNAL(multipleLoginDC(QString)),
&socket,SLOT(multipleLoginDCSlot(QString)),Qt::DirectConnection);
@Please have a look at the order you programmed your statements. From here it looks like you were 1. closing the socket, then 2. sending the router signal, that in turn calls the socket slot using a qt-connection (3. connected when last user logged in) to a temporary object from the stack (&socket). Probably this could cause the fault.
-
It may look wrong but
@
SharedData::clientByID
@binds id(QString) with client data object which is
@
#include <QString>class Client
{
public:
Client(QString,qint64);
QString ID;
qint64 clientType;
};
@and TcpSocket object still exists in it's own thread.
I think I will write it from scratch again. I had no idea it will be so much complicated :P
-
After a quite long time I tried to write it again and I found similar problem.
Now it is iterative server... It seems to be simplier to implement than concurrent server and it makes it better for the first time.
I have a problem with deleting objects deriving from QTcpSocket class in this code
@
CLIENT.CPP (part)
Client::Client(QObject* parent) :
QTcpSocket(parent)
{
this->av = false;
this->ID = QString();
this->clientType = 0;QObject::connect(this,SIGNAL(disconnected()),this,SLOT(disconnectedSlot())); QObject::connect(this,SIGNAL(readyRead()),this,SLOT(readyReadSlot()));
}
QString Client::readFromStream(){
QDataStream stream(this);
QString data = QString();
stream>>data;
return data;
}void Client::disconnectedSlot(){
emit clientDisconnected(this);
}void Client::readyReadSlot(){
emit clientReadyRead(this);
}LISTENER.CPP (part)
Listener::Listener(QObject *parent) :
QTcpServer(parent)
{
}void Listener::incomingConnection(int handle){
Client* client = new Client(this);
SharedData::clients.insert(client);
QObject::connect(client,SIGNAL(clientDisconnected(Client*)),this,SLOT(disconnectUnknown(Client*)));
QObject::connect(client,SIGNAL(clientReadyRead(Client*)),this,SLOT(readLoginData(Client*)));client->setSocketDescriptor(handle);
}
void Listener::readLoginData(Client client){
QString data = client->readFromStream();
QObject::disconnect(client,SIGNAL(clientReadyRead(Client)),this,SLOT(readLoginData(Client*)));parseLoginData(data,client);
}
void Listener::parseLoginData(QString data, Client *client){
// something emit loginDataReady(id,password,clientVersion,clientType,client);
}
void Listener::toAuthentication(QString id, QString password, QString clientVersion, qint64 clientType, Client* client){
// something if(!usersDb.open()){ //happens when not connected to database - currently it always isn't connected for testing purposes //sending errMsg client->disconnectFromHost(); //something } //something
}
void Listener::disconnectUnknown(Client *client){
SharedData::clients.remove(client); delete client;
}
@I want my Client objects to be destroyed when Client::disconnect() signal is emitted. But in this case when client->disconnectFromHost() is called i have an error:
"Screenshot with error":http://bronexproduction.pl/shared/error01.png
When I tried to just call
@delete client
@in different parts of code there was no problem with deleting. But it is not what I'm expecting.
-
Try using
@
client->deleteLater();
client = 0;
@ -
Like had said Andre use @client->deleteLater();@ instead of @delete client;@
And where are you making the connection with the slot Listener::incomingConnection(int handle) ? -
Thanks, that works :)
I'm not making a connection with Listener::incomingConnection(int handle), I only reimplemented virtual protected QTcpServer::incomingConnection(int handle) method, which is called automatically when a new connection is available.