IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Threads & Processus C++ Discussion :

Réseau multi-client avec threads


Sujet :

Threads & Processus C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    41
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 41
    Par défaut 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 : 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
    #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 : 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
    #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.
    Images attachées Images attachées    

  2. #2
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Primo, c'est du C++ et pas du C

    Secondo, avant de chercher si ça s'interchange vraiment, utilise stderr pour les sorties (ou rajoute un '\n" à la sortie de chaque sortie out) pour flusher.

    err est automatiquement synchrone, out ne l'est pas.

    Il est possible que ton progamme marche mais que les impresssions n'appariassent pas au bon endroit..

Discussions similaires

  1. Réponses: 0
    Dernier message: 25/07/2011, 17h45
  2. Code Client/serveur avec thread sur Android
    Par Narcistou dans le forum API standards et tierces
    Réponses: 1
    Dernier message: 21/04/2011, 11h25
  3. serveur TCP multi-clients threadé
    Par phobos64 dans le forum Réseau
    Réponses: 10
    Dernier message: 28/05/2009, 21h22
  4. serveur multi client avec fork()
    Par deby23 dans le forum Réseau
    Réponses: 17
    Dernier message: 11/09/2007, 16h32
  5. Probleme Serveur/Multi-client avec socket
    Par CouaC dans le forum Réseau
    Réponses: 9
    Dernier message: 18/06/2007, 00h49

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo