3 pièce(s) jointe(s)
Réseau multi-client avec threads
Bonjour,
Je suis en train de me créer un bête petit réseau dans lequel le client envoie un message au serveur et le serveur répond au client. Pour ça, j'ai utilisé expressément des threads pour mieux essayer de comprendre le mécanisme. Cependant, je me heurte à un problème assez gênant: les sockets s'interchangent pour je ne sais quelle raison. J'ai peut être une vague idée du pourquoi mais pas comment le résoudre. J'ai même fait des captures d'écran pour que vous puissiez mieux vous apercevoir du problème: 2 clients connectés au serveur. Chacun lui envoie un message et le serveur leur répond "ok". Comme vous pouvez le voir: lorsque le client se déconnecte, au lieu de fermer son socket, il ferme celui de l'autre client. Ce qui provoque une erreur chez l'autre client.
Et voici le code côté client et côté serveur:
Code:
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
| #include <iostream>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#define PORT 9999
int main(int argc, char *argv[]) {
struct hostent * host;
int serverSockfd;
struct sockaddr_in serverAddress;
if((host = gethostbyname("MacBook-Air-de-Gaspar-Feron.local")) == NULL) {
std::cerr << "[Erreur] Récupération du nom de la machine locale";
return EXIT_FAILURE;
}
if((serverSockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
std::cerr << "[Erreur] Création d'un socket";
return EXIT_FAILURE;
}
std::cout << "Le socket " << serverSockfd << " du serveur est ouvert." << std::endl;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr = *((struct in_addr *) host->h_addr);
memset(&serverAddress.sin_zero, '\0', 8);
if(connect(serverSockfd, (struct sockaddr *) &serverAddress, sizeof(struct sockaddr)) == -1) {
std::cerr << "[Erreur] Connexion au serveur";
return EXIT_FAILURE;
}
char * ip = (char *) inet_ntoa(serverAddress.sin_addr);
std::cout << "Client connecté avec le socket " << serverSockfd << " depuis " << ip << "." << std::endl;
/* - */
char message[128];
fgets(message, sizeof(message), stdin);
send(serverSockfd, message, strlen(message), 0);
char answer[128];
size_t nbrBytes;
if((nbrBytes = recv(serverSockfd, answer, sizeof(answer)-1, 0)) == -1) {
std::cerr << "[Erreur] Réception de la réponse du server";
return EXIT_FAILURE;
}
answer[nbrBytes] = '\0';
std::cout << "\"" << answer << "\"" << std::endl;
/* - */
close(serverSockfd);
std::cout << "Fermeture du socket du serveur " << serverSockfd << "." << std::endl;
return EXIT_SUCCESS;
} |
Code:
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
| #include <iostream>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h>
#define BACKLOG 20
#define PORT 9999
class Server {
private:
int serverSockfd_;
struct sockaddr_in serverAddress_;
public:
int start();
int clients();
};
void * client(void * p) {
int * clientSockfd = (int *) p;
while(true) {
std::cout << "Je suis un client !" << std::endl;
char message[128];
size_t nbrBytes;
if((nbrBytes = recv(*clientSockfd, message, sizeof(message)-1, 0)) == -1) {
std::cerr << "[Erreur] Réception d'un message dans un thread client.";
break;
}
message[nbrBytes] = '\0';
std::cout << nbrBytes << " byte" << (nbrBytes > 1 ? "s" : "") << " reçu" << (nbrBytes > 1 ? "s" : "") << " du client " << *clientSockfd << ": " << message << std::endl;
const char * answer = "Ok";
send(*clientSockfd, answer, strlen(answer), 0);
break;
}
close(*clientSockfd);
std::cout << "Fermeture du socket du client " << *clientSockfd << "." << std::endl;
return NULL;
}
int Server::start() {
int yes = 1;
if((serverSockfd_ = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
std::cerr << "[Erreur] Création d'un socket";
return EXIT_FAILURE;
}
std::cout << "Le socket " << serverSockfd_ << " du serveur est ouvert." << std::endl;
if(setsockopt(serverSockfd_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
std::cerr << "[Erreur] -setsockopt-";
return EXIT_FAILURE;
}
serverAddress_.sin_family = AF_INET;
serverAddress_.sin_port = htons(PORT);
serverAddress_.sin_addr.s_addr = INADDR_ANY;
memset(&serverAddress_.sin_zero, '\0', 8);
if(bind(serverSockfd_, (struct sockaddr *) &serverAddress_, sizeof(struct sockaddr)) == -1) {
std::cerr << "[Erreur] Liaison d'un socket à un port";
return EXIT_FAILURE;
}
if(listen(serverSockfd_, BACKLOG) == -1) {
std::cerr << "[Erreur] Attente de connexions extérieures";
return EXIT_FAILURE;
}
std::cout << "Le serveur est à l'écoute du port " << PORT << "." << std::endl;
/* - */
clients();
/* - */
close(serverSockfd_);
std::cout << "Fermeture du socket du serveur " << serverSockfd_ << "." << std::endl;
return EXIT_SUCCESS;
}
int Server::clients() {
unsigned int sinSize = sizeof(struct sockaddr_in);
while(true) {
int clientSockfd;
struct sockaddr_in clientAddress;
pthread_t clientThread;
std::cout << "Attente de la connexion d'un client sur le port " << PORT << "." << std::endl;
if((clientSockfd = accept(serverSockfd_, (struct sockaddr *) &clientAddress, &sinSize)) == -1) {
std::cerr << "[Erreur] Acceptation d'une demande de connexion extérieure";
return EXIT_FAILURE;
}
char * ip = (char *) inet_ntoa(clientAddress.sin_addr);
std::cout << "Client connecté avec le socket " << clientSockfd << " depuis " << ip << "." << std::endl;
/* - */
pthread_create(&clientThread, NULL, client, (void *) &clientSockfd);
/* - */
}
return EXIT_SUCCESS;
}
int main(int argc, char *argv[]) {
Server myServ;
myServ.start();
return EXIT_SUCCESS;
} |
Désolé pour le code qui n'est pas très structuré.
Et merci de votre aide. :)