Bonjour à tous,
J’ai réalisé un petit programme Client-Serveur sou Qt mais en utilisant pthread pour permettre une indépendance du Framework Qt et surtout pour la portabilité.
Voici les fichiers Du serveur
Fichier header.h : ce fichire contient les inclusions communes et quelques define
Le fichier classserver.h
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
65
66
67
68
69
70
71
72
73 #ifndef HEADER_H #define HEADER_H // On inclut les fichiers standards #include <iostream> #include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <thread> #include <mutex> //Les Fichiers Qt #include <QPlainTextEdit> #include <QPushButton> #define PORT 10000 #if defined (WIN32) //Si nous sommes sous WINDOWS #include <winsock2.h> #include <windows.h> //On peut remarquer que le type socklen_t qui existe sous Linux, n'est pas défini sous Windows. Ce type sert à stocker la taille d'une structures de type sockaddr_in. Ça n'est rien d'autre qu'un entier mais il nous évitera des problèmes éventuels de compilation sous Linux par la suite. Il va donc falloir le définir nous même à l'aide du mot clef typedef comme il suit typedef int socklen_t; #elif defined (linux) //Si nous sommes sous LINUX #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> // Define, qui nous serviront par la suite #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define closesocket(s) close(s) // De même typedef int SOCKET; typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr SOCKADDR; #endif struct Personnage { char nom[256]; char prenom[256]; int age; }; typedef struct Personnage Personnage; struct Shared { int data; pthread_mutex_t mut; pthread_cond_t synchro; }; struct ThreadData { QPlainTextEdit *strucPlainText; QPushButton *strucBtnOn; QPushButton *strucBtnOff; struct Shared *psh; }; struct MsgData { char nom[256]; char message[256]; }; #endif // HEADER_H
Le fichier classserver.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 #ifndef CLASSSERVER_H #define CLASSSERVER_H #include "header.h" #include <QDebug> #include <QPlainTextEdit> #include <QString> class ClassServer { private: unsigned temp = GetConsoleOutputCP(); /* Socket et contexte d'adressage du serveur */ static SOCKET sock; static SOCKADDR_IN sin; static socklen_t recsize; /* Socket et contexte d'adressage du client */ static SOCKET csock; static SOCKADDR_IN csin; static socklen_t crecsize; static int sock_err; static QPlainTextEdit *m_plainTextEdit ; static struct ThreadData m_threadData; static bool m_graphic; static struct MsgData m_msgDataServer; public: ClassServer(); ClassServer(struct ThreadData &myThreadData); ~ClassServer(); static bool Initialisation(); static void* FctListenClient(void *); static void FctSendMessage(struct MsgData &); static bool FctDeconnect(); }; #endif // CLASSSERVER_H
Ensuite voici le mainwindowserver.h
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276 #include "classserver.h" SOCKET ClassServer::sock = 0; SOCKADDR_IN ClassServer::sin; socklen_t ClassServer::recsize = sizeof(sin); SOCKET ClassServer::csock = 0; SOCKADDR_IN ClassServer::csin =SOCKADDR_IN(); socklen_t ClassServer::crecsize = sizeof(csin); int ClassServer::sock_err = 0; QPlainTextEdit* ClassServer::m_plainTextEdit = nullptr; struct ThreadData ClassServer::m_threadData; bool ClassServer::m_graphic = false; struct MsgData ClassServer::m_msgDataServer; //Constructeur par défaut ClassServer::ClassServer() { m_graphic = false; } //Constructeur avec la structure comme parametre ClassServer::ClassServer(struct ThreadData &myThreadData) { m_graphic = true; m_threadData = myThreadData; } bool ClassServer::Initialisation() { SetConsoleOutputCP(CP_UTF8); //Si nous sommes sous WINDOWS int erreur; #if defined (WIN32) //De plus, on doit devrez ajouter, dans le début de notre fonction main, le code suivant pour pouvoir utiliser les sockets sous Windows WSADATA WSAData; //La fonction WSAStartup sert à initialiser la bibliothèque WinSock. La macro MAKEWORD transforme les deux entiers (d'un octet) qui lui sont passés en paramètres en un seul entier (de 2 octets) qu'elle retourne. Cet entier sert à renseigner la bibliothèque sur la version que l'utilisateur souhaite utiliser (ici la version 2,0). Elle retourne la valeur 0 si tout s'est bien passé erreur = WSAStartup(MAKEWORD(2,2), &WSAData); #elif erreur = 0; #endif bool retVal = false; if(!erreur) { // 1------------------------------------------------ Création de la socket------------------------------------------------// /*Pour créer la socket, il nous faudra utiliser la fonction socket avec le prototype suivant : * int socket(int domain, int type, int protocol);*/ //Comme dans notre cas nous utiliserons le protocole TCP/IP, notre fonction sera toujours : sock = socket(AF_INET, SOCK_STREAM, 0); // Si la socket est valide if(sock != INVALID_SOCKET) { if(!m_graphic) printf("La socket %d est maintenant ouverte en mode TCP/IP\n", (unsigned int)sock); else { pthread_mutex_lock(&m_threadData.psh->mut); m_threadData.strucPlainText->appendPlainText(QString("La socket %1 est maintenant ouverte en mode TCP/IP\n").arg((unsigned int)sock)); pthread_mutex_unlock(&m_threadData.psh->mut); } // 2------------------------------------------------Paramétrer une socket------------------------------------------------// /* Après avoir déclaré et créé la socket, nous allons la paramétrer */ /* Configuration */ // SOCKADDR_IN sin; //Déja créée ci-dessus sin.sin_family = AF_INET; sin.sin_addr.S_un.S_addr = htonl(INADDR_ANY); sin.sin_port = htons(PORT); retVal = true; } else { if(!m_graphic) perror("socket"); else { pthread_mutex_lock(&m_threadData.psh->mut); m_threadData.strucPlainText->appendPlainText(QString("Erreur Socket : %1 ").arg(GetLastError())); pthread_mutex_unlock(&m_threadData.psh->mut); } } } return retVal; } //Déstructeur ClassServer::~ClassServer() { SetConsoleOutputCP(temp); } //La fonction LISTEN void* ClassServer::FctListenClient(void *arg) { // 3------------------------------------------------Établir une connexion avec le client*------------------------------------------------// /*Enfin, pour associer à la socket ces informations, nous allons utiliser la fonction : * int bint(int socket, const struct sockaddr* addr, socklen_t addrlen); */ (void *)arg; int theStatus = 1; //Donc, nous ferons toujours ainsi : sock_err = bind(sock, (SOCKADDR *)&sin, recsize); /* Si la socket ne fonctionne pas*/ if(sock_err == SOCKET_ERROR) { //On appelle la fonction FctThreadListenClient if(m_graphic) { //pthread_mutex_lock(&m_threadData.psh->mut); m_threadData.strucPlainText->appendPlainText(QString("Erreur : bind : %1 ").arg(GetLastError())); //pthread_mutex_unlock(&m_threadData.psh->mut); } } /* Si la socket fonctionne */ else { // 4------------------------------------------------Établir une ecoute avec le client------------------------------------------------// //Démarrage du listage (mode server) bool stopWhile = true; sock_err = listen(sock, 5); qDebug() << " sock_err = " << sock_err; if(m_graphic) { m_threadData.strucPlainText->appendPlainText(QString("Listage du port %1...\n").arg(PORT)); } /* Si la socket fonctionne en LISTEN*/ if(sock_err != SOCKET_ERROR) { // On utilisera la fonction comme cela : // Attente pendant laquelle le client se connecte if(m_graphic) { m_threadData.strucPlainText->appendPlainText(QString("Patientez pendant que le client se connecte sur le port %1 ").arg(PORT)); } while(stopWhile) { csock = accept(sock, (SOCKADDR*)&csin, &crecsize); //Avec "csock" représentant la socket client et "csin" son contexte d'adressage. //Si CSOCK est une invalide socket if(csock == INVALID_SOCKET) { if(m_graphic) { //pthread_mutex_lock(&m_threadData.psh->mut); m_threadData.strucPlainText->appendPlainText(QString("Problème de création de socket client")); //pthread_mutex_unlock(&m_threadData.psh->mut); } stopWhile = false; } //Si CSOCK est une valide socket else { if(m_graphic) { m_threadData.strucPlainText->appendPlainText(QString("Un client se connecte avec la socket %1 de %2 : %3\n").arg((int)csock).arg(inet_ntoa(csin.sin_addr)).arg(htons(csin.sin_port))); } } /* Si CSOCK est une valide socket */ } /* la boucle WHILE */ } /* Si la socket ne fonctionne pas en LISTEN*/ else { if(m_graphic) { m_threadData.strucPlainText->appendPlainText(QString("Erreur Listen")); } } void *retval = nullptr; }/* Si la socket fonctionne */ //return nullptr; pthread_exit((void*)(theStatus)); } void ClassServer::FctSendMessage(struct MsgData &msgData) { sock_err = send(csock, (char*)&msgData, sizeof(msgData), 0); if(sock_err != SOCKET_ERROR ) { qDebug() << "Le message a bien était envoyé"; } else { qDebug() << "Le message n'a pas était envoyé"; } } bool ClassServer::FctDeconnect() { // 4------------------------------------------------Fermer la connexion------------------------------------------------// /*Finalement nous terminerons par la fonction closesocket qui permet de fermer une socket. * int closesocket(int sock); * Son prototype est très simple, je pense donc que la fonction se passe de commentaires.*/ //Fermeture de la socket client et de la socket serveur bool retVal = false; //Fermeture de la socket client qDebug() << "csock in deconnect = " << csock; if(csock != INVALID_SOCKET) { if(!closesocket(csock)) { if(m_graphic) { //pthread_mutex_lock(&m_threadData.psh->mut); m_threadData.strucPlainText->appendPlainText("Fermeture de la socket client."); //pthread_mutex_unlock(&m_threadData.psh->mut); } retVal = true; } else { if(m_graphic) { //pthread_mutex_lock(&m_threadData.psh->mut); m_threadData.strucPlainText->appendPlainText("La socket client n'a pas été fermée."); //pthread_mutex_unlock(&m_threadData.psh->mut); } retVal = false; } } //Fermeture de la socket serveur if(!closesocket(sock)) { if(m_graphic) { //pthread_mutex_lock(&m_threadData.psh->mut); m_threadData.strucPlainText->appendPlainText("Fermeture de la socket serveur."); //pthread_mutex_unlock(&m_threadData.psh->mut); } retVal = true; } else { if(m_graphic) { //pthread_mutex_lock(&m_threadData.psh->mut); m_threadData.strucPlainText->appendPlainText("La socket serveur n'a pas été fermée."); //pthread_mutex_unlock(&m_threadData.psh->mut); } retVal = false; } if(!m_graphic) { m_threadData.strucPlainText->appendPlainText("Fermeture du serveur terminée."); } //Si nous sommes sous WINDOWS #if defined (WIN32) //Cette fonction va simplement libérer les ressources allouées par la fonction WSAStartup(). WSACleanup(); #endif return retVal; }
Enfin voici le main.cpp pas grande chose dedans
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 #ifndef MAINWINDOWSERVER_H #define MAINWINDOWSERVER_H #include <QMainWindow> #include <QMessageBox> #include "threadFunctions.h" namespace Ui { class MainWindowServer; } class MainWindowServer : public QMainWindow { Q_OBJECT public: explicit MainWindowServer(QWidget *parent = nullptr); ~MainWindowServer(); void FctConnections(); public slots: void SlotStartServer(); void SlotSendMessage(); void SlotDeconnexion(); private: Ui::MainWindowServer *ui; ClassServer myClassServer; //On déclare les thread pthread_t threadListen; struct Shared m_shared; struct ThreadData m_threadData; struct MsgData m_msgDataServer; }; #endif // MAINWINDOWSERVER_H voici le fichier mainwindowserver.cpp #include "mainwindowserver.h" #include "ui_mainwindowserver.h" MainWindowServer::MainWindowServer(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindowServer) { ui->setupUi(this); m_shared = { .data = 0, .mut = PTHREAD_MUTEX_INITIALIZER, .synchro = PTHREAD_COND_INITIALIZER, }; m_threadData = { .strucPlainText = ui->plainTextEditRapport, .strucBtnOn = ui->btnLancer, .strucBtnOff = ui->btnDeconnecter, .psh = &m_shared, }; FctConnections(); } MainWindowServer::~MainWindowServer() { pthread_cancel(threadListen); delete ui; //delete myClassServer; } void MainWindowServer::FctConnections() { QObject::connect(ui->btnLancer, SIGNAL(clicked()), this, SLOT(SlotStartServer())); QObject::connect(ui->btnDeconnecter, SIGNAL(clicked()), this, SLOT(SlotDeconnexion())); QObject::connect(ui->btnEnvoyer, SIGNAL(clicked()), this, SLOT(SlotSendMessage())); } void MainWindowServer::SlotStartServer() { //myClassServer = ClassServer((QPlainTextEdit*)ui->plainTextEditRapport); myClassServer = ClassServer(m_threadData); if(myClassServer.Initialisation()) { //Lancement de l'écoute du serveur int ret = pthread_create(&threadListen, NULL, ClassServer::FctListenClient, nullptr); if(ret != 0) { ui->plainTextEditRapport->appendPlainText("Erreur : erreur de création de pthread_create()."); } else { ui->plainTextEditRapport->appendPlainText("Succés : Création de pthread réussie"); ui->btnLancer->setEnabled(false); ui->btnDeconnecter->setEnabled(true); } } } void MainWindowServer::SlotSendMessage() { strcpy(m_msgDataServer.nom, "Serveur"); strcpy(m_msgDataServer.message, ui->lineEditMessage->text().toStdString().c_str()); ClassServer::FctSendMessage(m_msgDataServer); } void MainWindowServer::SlotDeconnexion() { //pthread_cancel(threadListen); if(myClassServer.FctDeconnect()) { ui->btnDeconnecter->setEnabled(false); ui->btnLancer->setEnabled(true); } //Just pour tester l'arret du thread if(pthread_cancel(threadListen)) qDebug() << "threadListen arreter"; else qDebug() << "threadListen pas arreter"; }
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 #include "mainwindowserver.h" #include <QApplication> #include <QLocale> #include <QTranslator> int main(int argc, char *argv[]) { QApplication a(argc, argv); QTranslator translator; const QStringList uiLanguages = QLocale::system().uiLanguages(); for (const QString &locale : uiLanguages) { const QString baseName = "SocketGraphicServer_" + QLocale(locale).name(); if (translator.load(":/i18n/" + baseName)) { a.installTranslator(&translator); break; } } MainWindowServer w; w.show(); return a.exec(); }
Maintenant voici les fichiers Du côté client
Fichier classclient.h
Fichier classclient.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 #ifndef CLASSCLIENT_H #define CLASSCLIENT_H #include "../SocketGraphicServer/header.h" #include <QDebug> #include <QPlainTextEdit> #include <QString> #include <QMessageBox> class ClassClient { unsigned temp = GetConsoleOutputCP(); /* Socket et contexte d'adressage du client */ static SOCKET csock; static SOCKADDR_IN csin; static socklen_t crecsize; static int sock_err; static QPlainTextEdit *m_plainTextEdit ; static struct ThreadData m_threadDataClient; static bool m_graphic; static struct MsgData m_msgDataClient; static bool boolConnection; public: ClassClient(); ClassClient(struct ThreadData &myThreadData); ~ClassClient(); static void Initialisation(); static bool FctConnection(); static void FctDeconnection(); static void* FctReceiveMsg(void*); }; #endif // CLASSCLIENT_H
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 #include "classclient.h" SOCKET ClassClient::csock = 0; SOCKADDR_IN ClassClient::csin; socklen_t ClassClient::crecsize = sizeof(csin); int ClassClient::sock_err; QPlainTextEdit *m_plainTextEdit = nullptr ; struct ThreadData ClassClient::m_threadDataClient; bool ClassClient::m_graphic = false; struct MsgData ClassClient::m_msgDataClient; bool ClassClient::boolConnection = false; ClassClient::ClassClient() { m_graphic = false; Initialisation(); } ClassClient::ClassClient(struct ThreadData &myThreadData) { m_graphic = true; m_threadDataClient = myThreadData; Initialisation(); } ClassClient::~ClassClient() { SetConsoleOutputCP(temp); } void ClassClient::Initialisation() { SetConsoleOutputCP(CP_UTF8); #if defined (WIN32) WSADATA WSAData; int erreur = WSAStartup(MAKEWORD(2,2), &WSAData); #elif int erreur = 0; #endif if(!erreur) { /* Création de la socket */ csock = socket(AF_INET, SOCK_STREAM, 0); printf("La socket client est %d\n", csock); /* Configuration de la connexion */ csin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //127.0.0.1"); "192.168.0.12" csin.sin_family = AF_INET; csin.sin_port = htons(PORT); } } bool ClassClient::FctConnection() { m_threadDataClient.strucPlainText->appendPlainText(QString("je suis la connection")); bool returnVal = false; //Si on n'arrive pas à se connecter. if(connect(csock, (SOCKADDR *)&csin, sizeof(csin)) == SOCKET_ERROR) { //printf("Connexion à %s sur le port %d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); // Attente pendant laquelle le client se connecte if(!m_graphic) printf("Impossible de se connecter."); else m_threadDataClient.strucPlainText->appendPlainText(QString("Impossible de se connecter.")); returnVal = false; } //Si on arrive à se connecter else { if(!m_graphic) printf("Connexion à %s sur le port %d\n", inet_ntoa(csin.sin_addr), htons(csin.sin_port)); else { m_threadDataClient.strucPlainText->appendPlainText(QString("Connexion à %1 sur le port %2.").arg(inet_ntoa(csin.sin_addr)).arg(htons(csin.sin_port))); } returnVal = true; boolConnection = true; } return returnVal; } void ClassClient::FctDeconnection() { /* On ferme la socket précédemment ouverte */ closesocket(csock); //QMessageBox::information(nullptr, "csock", QString::number(csock)); #if defined (WIN32) WSACleanup(); #endif boolConnection = false; m_threadDataClient.strucPlainText->appendPlainText(QString("Déconnexion")); } void* ClassClient::FctReceiveMsg(void *arg) { qDebug() << "j'attends un message avant le while" ; //m_msgDataClient = (MsgData*)arg; while(boolConnection) { if(recv(csock, (char*)&m_msgDataClient, sizeof(m_msgDataClient), 0) != SOCKET_ERROR) { std::string nom = m_msgDataClient.nom; std::string message = m_msgDataClient.message; qDebug() << QString::fromStdString(nom); qDebug() << QString::fromStdString(message); if(!m_graphic) printf("Connexion à %s sur le port %d\n", inet_ntoa(csin.sin_addr), htons(csin.sin_port)); else { pthread_mutex_lock(&m_threadDataClient.psh->mut); m_threadDataClient.strucPlainText->appendPlainText(QString(QString::fromStdString(nom) + " : " + QString::fromStdString(message))); pthread_mutex_unlock(&m_threadDataClient.psh->mut); } } } //On arrete le thread //pthread_exit(arg); }
Fichier mainwindowclient.h
Le fichier mainwindowclient.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 #ifndef MAINWINDOWCLIENT_H #define MAINWINDOWCLIENT_H #include <QMainWindow> #include "threadFunctions.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindowClient; } QT_END_NAMESPACE class MainWindowClient : public QMainWindow { Q_OBJECT public: MainWindowClient(QWidget *parent = nullptr); ~MainWindowClient(); void FctConnectionsObjets(); void FctRcvMsg(); public slots: void SlotRcvMsg(); void SlotConnection(); void SlotDeconnexion(); private: Ui::MainWindowClient *ui; ClassClient myClassClient; //On déclare les thread pthread_t threadRcvMsg; //Les structures struct Shared m_shared; struct ThreadData m_threadDataClient; }; #endif // MAINWINDOWCLIENT_H
Fichier main.cpp cote client
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
65
66
67 #include "mainwindowclient.h" #include "ui_mainwindowclient.h" MainWindowClient::MainWindowClient(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindowClient) { ui->setupUi(this); qDebug() << "entrée du constructeur"; m_shared = { .data = 0, .mut = PTHREAD_MUTEX_INITIALIZER, .synchro = PTHREAD_COND_INITIALIZER, }; m_threadDataClient = { .strucPlainText = ui->plainTextEditRapport, .strucBtnOn = ui->btnConDecon, .strucBtnOff = ui->btnDeconnecter, .psh = &m_shared, }; myClassClient = ClassClient(m_threadDataClient); FctConnectionsObjets(); } MainWindowClient::~MainWindowClient() { delete ui; } void MainWindowClient::FctConnectionsObjets() { QObject::connect(ui->btnConDecon, SIGNAL(clicked()), this, SLOT(SlotConnection())); QObject::connect(ui->btnDeconnecter, SIGNAL(clicked()), this, SLOT(SlotDeconnexion())); } void MainWindowClient::SlotConnection() { //myClassClient = ClassClient(m_threadDataClient); if(myClassClient.FctConnection()) { ui->btnConDecon->setText("&Déconnecter"); SlotRcvMsg(); } } void MainWindowClient::SlotRcvMsg() { int ret = pthread_create(&threadRcvMsg, NULL, ClassClient::FctReceiveMsg, nullptr); if(ret != 0) { ui->plainTextEditRapport->appendPlainText("Erreur : erreur de création de pthread_create() de \"threadRcvMsg\"."); } else { ui->plainTextEditRapport->appendPlainText("Succés : Création de pthread \"threadRcvMsg\" réussie"); } } void MainWindowClient::SlotDeconnexion() { ui->btnConDecon->setText("&Connecter"); myClassClient.FctDeconnection(); }
Et voici mes 2 problèmes :
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 #include "mainwindowclient.h" #include <QApplication> #include <QLocale> #include <QTranslator> int main(int argc, char *argv[]) { QApplication a(argc, argv); QTranslator translator; const QStringList uiLanguages = QLocale::system().uiLanguages(); for (const QString &locale : uiLanguages) { const QString baseName = "SocketGraphicClient_" + QLocale(locale).name(); if (translator.load(":/i18n/" + baseName)) { a.installTranslator(&translator); break; } } MainWindowClient w; w.show(); return a.exec(); }
Problème 1 :
Je lance le serveur je me connecte et je peux envoyer des messages,
Le souci c’est du coté du client que lui reçoit les messages et j’arrive à les affichés avec des qDebug() avec cette fonction coté client
Mais quand j’essaye de les affichés avec
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 void* ClassClient::FctReceiveMsg(void *arg) { qDebug() << "j'attends un message avant le while" ; //m_msgDataClient = (MsgData*)arg; while(boolConnection) { if(recv(csock, (char*)&m_msgDataClient, sizeof(m_msgDataClient), 0) != SOCKET_ERROR) { std::string nom = m_msgDataClient.nom; std::string message = m_msgDataClient.message; qDebug() << QString::fromStdString(nom); qDebug() << QString::fromStdString(message); if(!m_graphic) printf("Connexion à %s sur le port %d\n", inet_ntoa(csin.sin_addr), htons(csin.sin_port)); else { pthread_mutex_lock(&m_threadDataClient.psh->mut); m_threadDataClient.strucPlainText->appendPlainText(QString(QString::fromStdString(nom) + " : " + QString::fromStdString(message))); pthread_mutex_unlock(&m_threadDataClient.psh->mut); } } } //On arrete le thread //pthread_exit(arg); }le programme crash avec cette erreur
Code : Sélectionner tout - Visualiser dans une fenêtre à part m_threadDataClient.strucPlainText->appendPlainText(QString(QString::fromStdString(nom) + " : " + QString::fromStdString(message)));
Pourtant le
Code : Sélectionner tout - Visualiser dans une fenêtre à part D:/Fichiers_applications/C++/Projets_QtCreator/Test/Revis_gnrle/Travaux_pratiques/SocketGraphic/build-SocketGraphicRoot-Desktop_Qt_6_3_1_MinGW_64_bit-Debug/SocketGraphicClient/debug/SocketGraphicClient.exe crashed.
est utilisé dans les autres fonctions et qui marche très bien, comme dans cette fonction.
Code : Sélectionner tout - Visualiser dans une fenêtre à part m_threadDataClient.strucPlainText->appendPlainText(QString("Déconnexion"));
Je n’arrive pas à trouver pourquoi ça crash
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 void ClassClient::FctDeconnection() { /* On ferme la socket précédemment ouverte */ closesocket(csock); //QMessageBox::information(nullptr, "csock", QString::number(csock)); #if defined (WIN32) WSACleanup(); #endif boolConnection = false; m_threadDataClient.strucPlainText->appendPlainText(QString("Déconnexion")); }
Mon deuxième problème est que :
Quand je connecte le serveur avec cette fonction
Et que je me déconnecte avec cette fonction
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 void MainWindowServer::SlotStartServer() { //myClassServer = ClassServer((QPlainTextEdit*)ui->plainTextEditRapport); myClassServer = ClassServer(m_threadData); if(myClassServer.Initialisation()) { //Lancement de l'écoute du serveur int ret = pthread_create(&threadListen, NULL, ClassServer::FctListenClient, nullptr); if(ret != 0) { ui->plainTextEditRapport->appendPlainText("Erreur : erreur de création de pthread_create()."); } else { ui->plainTextEditRapport->appendPlainText("Succés : Création de pthread réussie"); ui->btnLancer->setEnabled(false); ui->btnDeconnecter->setEnabled(true); } } }
La première fois se passe très bien, mais si je me déconnecte et que j’essaye de me reconnecter plus de deux fois ça crash aussi.
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 void MainWindowServer::SlotDeconnexion() { //pthread_cancel(threadListen); if(myClassServer.FctDeconnect()) { ui->btnDeconnecter->setEnabled(false); ui->btnLancer->setEnabled(true); } //Just pour tester l'arret du thread if(pthread_cancel(threadListen)) qDebug() << "threadListen arreter"; else qDebug() << "threadListen pas arreter"; }
Merci d’avance de votre aide je coince depuis une semaine.
Merci à tous
Partager