Bonjour,
J'ai un petit problème avec le code ci-dessous:
server.hpp :
server.cpp :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 #ifndef SERVER_HPP #define SERVER_HPP #include <QTcpServer> #include <QTcpSocket> #include <QList> class Server : public QTcpServer { Q_OBJECT private slots: void addClient(); void removeClient(); private: QList<QTcpSocket *> clients; public: Server(quint16 port, QObject *parent=0); }; #endif /* PACKET_HPP */
main.cpp :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 #include "server.hpp" #include <QThread> #include <iostream> using namespace std; Server::Server(quint16 port, QObject *parent) : QTcpServer(parent) { if(listen(QHostAddress::Any, port)) { connect(this, SIGNAL(newConnection()), this, SLOT(addClient())); } return; } void Server::addClient() { cout << "addClient: current thread: " << QThread::currentThread() << endl; QTcpSocket *client=nextPendingConnection(); if(client!=NULL) { cout << "New connection" << endl; cout << "New client thread: " << client->thread() << endl; connect(client, SIGNAL(disconnected()), this, SLOT(removeClient())); clients.append(client); } return; } void Server::removeClient() { cout << "removeClient: current thread: " << QThread::currentThread() << endl; QList<QTcpSocket *>::iterator it; QTcpSocket *client=static_cast<QTcpSocket *>(sender()); for(it=clients.begin(); it!=clients.end(); ++it) { if(*it==client) { cout << "Disconnection" << endl; cout << "Client thread: " << client->thread() << endl; clients.erase(it); delete *it; //(*it)->deleteLater(); break; } } return; }
server.pro :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #include "server.hpp" #include <QCoreApplication> #define SERVER_PORT 45200 int main(int argc, char **argv) { QCoreApplication app(argc, argv); Server server(SERVER_PORT); return app.exec(); }
client.cpp :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8SOURCES+=main.cpp server.cpp HEADERS+=server.hpp TEMPLATE=app CONFIG=warn_on qt debug console QT=core network
client.pro :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #include <QTcpSocket> #include <iostream> using namespace std; int main(void) { QTcpSocket socket; socket.connectToHost("127.0.0.1", 45200); if(socket.waitForConnected(3000)) { socket.disconnectFromHost(); } else { cout << "Connection failed" << endl; } return 0; }
La compilation (sous Windows avec MinGW) se passe très bien deux exécutable sont créés (server.exe et client.exe). Dans un premier temps je lance le serveur puis je lance le client. Celui se connecte au serveur et ensuite se déconnecte. Cela à pour effet d'appeler le slot removeClient de la classe Server. Et c'est là que le problème survient: quand je fais un delete du QTcpSocket correspondant au client qui vient de se déconnecter j'ai un bon vieux segmentation fault. Si j'utilise deleteLater à la place du simple delete je n'ai plus de problème. J'aimerais comprendre pourquoi je ne peux pas faire directement un delete sur mon QTcpSocket. Dans la doc de Qt (dans la section Multithreaded Programming) il est dit, je cite :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7SOURCES+=client.cpp TEMPLATE=app CONFIG=warn_on qt console debug QT=core network
Or mon application n'est pas multithreadé et donc quand j'appelle delete sur le QTcpSocket l'objet ne peux être en train de traiter un évènement puisque je suis encore dans le slot removeClient et que par conséquent l'event loop n'a pas "la main". Voilà si quelqu'un peut m'expliquer en quoi mon raisonnement est incorrect je lui en serais reconnaissant.Calling delete on a QObject from another thread than the thread where it is created (or accessing the object in other ways) is unsafe unless you can guarantee that the object isn't processing events at the same moment.
PS: il semble que ce problème ne se produise pas sur Linux (Ubuntu et centOS).
Partager