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

Réseau C Discussion :

Socket TCP [Morpion multijoueurs]


Sujet :

Réseau C

  1. #1
    Candidat au Club
    Homme Profil pro
    elève-ingénieur
    Inscrit en
    Juillet 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : elève-ingénieur

    Informations forums :
    Inscription : Juillet 2011
    Messages : 8
    Points : 2
    Points
    2
    Par défaut Socket TCP [Morpion multijoueurs]
    Bonjour à la communauté developpez.

    Je viens à vous comme vous vous en doutez à cause d'un problème.
    En effet, j'essaie depuis quelques temps de finir un programme : Un Morpion-like en réseau.

    une rapide présentation :

    - Un serveur de jeu
    - un serveur d'authentification
    - un serveur client (le Gm qui est à la base un client décide du nombre de participants possible et des autres infos de la partie)

    Mon problème : J'arrive à créer la partie gràce au GM, l'authenfication fonctionne, les joueurs peuvent se connecter, pour l'instant je n'ai testé qu'avec 2 joueurs. Lorsqu'un des joueurs rentrent des coordonnées, la partie se stoppe pour lui, le 2e envoie ses coordonnées et là une segfault.

    Je ne maîtrise pas bien la mémoire partagée et les sémaphores, je pense que ma segfault peut provenir d'une mauvaise utilisation des sémaphores et des processus.

    Je fais donc appel à vous pour essayer de m'éclairer.


    Merci d'avance, les fichiers sont assez longs, donc je mets juste les deux plus importants.

    La socket joueur.
    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
     
    int main(int argc, char ** argv)
    {
     
      	struct sockaddr_in sin;
      	int sfd, ip; 
     
      	// On vérifie le nombre d'argument
      	if(argc != 3)
      	{
       	 	printf("usage : %s <ip> <port>\n", argv[0]);
        	return 1;
      	}
     
    	Participant participant;
    	memset(&participant, 0, sizeof(participant));
     
      	participant=interface();
     
      	// Ouverture du socket
      	if((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    	{
        	perror("socket");
        	return 3;
      	}
     
      	printf("Ouverture du socket %d...\n", sfd);
     
      	// Il faut convertir l'ip (comme dans le client udp) avec la fonction inet_pton
      	if(!inet_pton(AF_INET, IP, &ip))	
    	{
        	fprintf(stderr, "Le format de l'adresse IP donnee en argument est incorrect.\n");
     
    		return 4;
      	}
     
      	// Description du serveur sur lequel on veut se connecter
      	sin.sin_addr.s_addr = ip;
      	sin.sin_port = htons(PORT);
      	sin.sin_family = AF_INET;
     
      	// Connexion au serveur
      	if(connect(sfd, (struct sockaddr*)&sin, sizeof(struct sockaddr)) == -1)
    	{
        	perror("connect");
        	close(sfd);
        	//close(fd);
        	return 5;
      	}
     
    	printf("Connexion au serveur de jeu\n");
     
    	if(send(sfd, &participant, sizeof(Participant), 0) == -1) 
    	{
    	 	perror("sendstruct");
    	  	close(sfd);
    	  	//close(fd);
    	  	return 5; 
      	}
     
    	printf("Données envoyées\n");
     
    	int resultauth;  
     
    	if(recv(sfd, &resultauth, sizeof(int), 0) == -1) 
    	{
    		perror("result");
    	  	close(sfd);
     
    		return 6;
      	}
     
    	printf("Réception réponse du serv...%d\n", resultauth);
     
      	Partie partie;
      	memset(&partie, 0, sizeof(Partie));
     
      	int reponse; 
     
    	switch(resultauth) 
    	{
    	  	case 0 : //on teste ici, dans le cas ou la partie existe dans la mémoire partagée et que le GM a accepté le joueur.
    		if(recv(sfd, &reponse, sizeof(int), 0) == -1) 
    		{
    			perror("receptclientreponse");
    			return 12;
    		}
    			if(reponse == 1) 
    			{
    		  		interface_joueur(PORT);
     
    				int i;
     
    				if(recv(sfd, &i, sizeof(int), 0)== -1) 
    		  		{
    			  		perror("erreur ID");
    			 		return 13;
    		  		}
     
    		  		printf("Reception taille\n");
     
    				fprintf(stderr, "Lancement de la partie...\n");
     
     
    		 		//boucle infinie pour le test
    				while(1) 
    				{
    		  			int l=0; 
    		  			int c=0;
     
    					do 
    					{
    						printf("La partie est de type %dx%d, Entrez les coordonnées : ", i-1, i-1);
     
    						printf("\n");
    						fprintf(stderr, "Ligne : ");
    		  				scanf("%d", &l);
    		  				fprintf(stderr, "Colonne : "); 
    		  				scanf("%d", &c);
    					} while ((c>(i-1)) | (l>(i-1)));
     
    		  			if(send(sfd, &l, sizeof(int), 0) == -1 || send(sfd, &c, sizeof(int), 0) == -1)
    		  			{
    			  			perror("envoie coord");
    			  			return 14;
    		  			}
     
    		  			printf("Coordonnees envoyees\n");
     
    		  			int **partie;
    		  			partie=creer_tableau(i);
     
    					if(recv(sfd, &partie, sizeof(partie), 0) == -1) 
    					{
    						perror("erreur partie");
    						return 15;
    		  			}
     
    	  				printf("partie reçue");	
    		 			affiche_partie(partie, i);
    				}	  
     
    		 	}
    			else 
    			{ 
    				printf("connexion refusée par le gm\n");
    				close(sfd);
    				return 13;
    		  	}
     
    			break;
     
    	  case 1 : 
     
    			partie=interface_GM(); 
    		   	//on envoie la partie dans la mémoire partagée.			
    		   	if(send(sfd, &partie, sizeof(Partie), 0) == -1) 
    		   	{
    			   perror("sendpartie");
    			   return 7;
    		   	}
     
    			printf("Envoie de la partie au serveur\n");
     
    		   	int mem_ID;
    		   	//Reception de la cle de la mémoire partagée
    		   	if(recv(sfd, &mem_ID, sizeof(int), 0) == -1) 
    			{
    				perror("receptionclef");
    				return 8;
    			}
    		   	printf("id reçue...%d\n", mem_ID);
     
    		   	Serveur_GM(mem_ID, partie.participants, partie.taille);
     
    			break;
     
    	  case 2 : 
     
    			printf("Erreur id ou mdp, au revoir\n"); close(sfd); 
     
    			break;
     
    	  case 3 : 
     
    			printf("ce compte n'existe pas, au revoir\n");
      close(sfd); 
     
    			break;
    	}  
     
    return 0;  
     
    }
    La socket 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
    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
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
     
    int main(int argc, char ** argv)
    {
     
      	// Description du serveur
      	struct sockaddr_in ssin;
      	int sfd, ip;
     
      	// Description du client
      	struct sockaddr_in csin;
      	int csfd;
      	socklen_t crecsize = sizeof(struct sockaddr_in);
     
      	Participant participant; 
      	memset(&participant, 0, sizeof(participant));
      	int x;
     
      	// Vérification du nombre d'arguments
      	if(argc != 3)
      	{
        	printf("usage : %s <ip> <port>\n", argv[0]);
        	return 1;
      	}
     
      	// Création de la socket (voir le client UDP pour les détails des args)
      	sfd = socket(AF_INET, SOCK_STREAM, 0);
       	if(sfd == -1)
    	{
        	perror("socket");
        	return 2;
      	}
     
      	printf("Le socket %d est maintenant ouvert en mode TCP/IP...\n", sfd);
     
      	if(!inet_pton(AF_INET, IP, &ip))
    	{
        	fprintf(stderr, "Le format de l'adresse IP donnee en argument est incorrect.\n");
        	return 4;
    	}
     
      	// Paramètrage du port du serveur
      	ssin.sin_addr.s_addr = ip;
      	ssin.sin_family = AF_INET;
      	ssin.sin_port = htons(PORT);
     
      	// Ensuite il faut lier le socket à la description du port
      	if(bind(sfd, (struct sockaddr*)&ssin, sizeof(struct sockaddr)) == -1)
    	{
        	perror("bind");
        	return 3;
      	}
     
      	printf("Socket lie au port %d...\n", PORT);
     
      	// Nous allons maintenant mettre le socket "sur écoute", c'est à dire que ce
      	// socket va servir de "porte d'entrée" aux clients qui voudront se connecter
      	// et qui seront ensuite basculer sur un autre socket afin de ne pas bloquer
      	// la socket mise en écoute.
      	// Fonction listen :
      	// arg 1 : fd de la socket que l'on va passer en mode écoute
      	// arg 2 : le nombre de connexion maximum en attente de connexion (que l'on
      	//         verra plus tard, avec la fonction "accept"). Ici, nous accepterons
      	//         au maximum 5 clients en attente
      	if(listen(sfd, 5) == -1)
    	{
        	perror("listen");
        	return 4;
      	}
     
    	printf("Le socket %d est maintenant en mode ecoute...\n", sfd);
     
    	//Déclaration de la structure mémoire partagée
    	Mem_partagee mem_partagee;
    	int mem_ID;
    	memset(&mem_partagee, 0, sizeof(mem_partagee));
     
    	//Création de la clef identifiant la mémoire patagée
    	int CLEF=10;
    	key_t clef;
    	clef = ftok(argv[0], CLEF);
     
    	//On crée le sémaphore
    	int semid=semget (clef, 2, IPC_CREAT | IPC_EXCL | 0666);
    	semctl(semid, 0, SETVAL, 1);
    	sembuf op;
    	sembuf opp;
     
    	op.sem_num = 0;//numéro de notre sémaphore
    	op.sem_op  = -1;//Pour un P() on décrémente
    	op.sem_flg = 0;
     
    	opp.sem_num = 0;
    	opp.sem_op  = 1;
    	opp.sem_flg = 0;
     
    	//Création de la mémoire partagée
    	mem_ID=creer_mempartagee(clef);
    	if(mem_ID == -1) 
    	{
    		perror("mem_parta");	
    		return 7;
    	}
     
    	void* ptr_mem_partagee;
    	printf("Memoire  partagée crée\n");
     
    	if((ptr_mem_partagee = shmat(mem_ID, NULL, 0)) == (void *) -1) 
    	{
    		perror("shmat");
    		return 9;
    	}
     
    	*((Mem_partagee*)ptr_mem_partagee) = mem_partagee;
     
    	while(1)
    	{
        	printf("En attente de la tentative de connexion d'un client sur le port %d...\n", PORT);
     
        	// Fonction accept : C'est une fonction bloquante, c'est à dire que 
        	// le programme reste bloqué dans cette fonction tant qu'aucun client
        	// ne s'est pas connecté.
        	// arg 1 : le fd de la socket passée en mode écoute
        	// arg 2 : la structure dans laquelle la fonction va décrire le client
        	// arg 3 : la taille de la structure de l'arg 2
        	// Cette fonction renvoie un socket qui va servir d'interface
        	// avec le client. Nous n'utiliseront donc plus la variable "sfd" pour
        	// communiquer avec le client, mais "csfd". "sfd" restera en écoute pour
        	// "orienter" les clients qui se connectent vers d'autres sockets
        	csfd = accept(sfd, (struct sockaddr*)&csin, &crecsize);
     
        	if(csfd == -1)
    		{
          		perror("accept");
          		return 5;
        	}
     
    		printf("Nouveau client, connecte au socket %d depuis %s:%d...\n", csfd, inet_ntoa(csin.sin_addr), htons(csin.sin_port));
     
        	x=fork();
        	// Il y a eu une erreur, on ferme le serveur (et le socket ouvert !)
     
    		if(x<0)
    		{
          		perror("fork");
          		close(sfd);
          		return 6;
        	}
     
        	// On gère le père
        	else if(x>0)
    		{
          	// On ferme le socket client pour ce processus, on en a plus besoin
         	close(csfd);
          	continue; // Mot clé qui permet d'à aller directement à la fin du corps de la boucle
        	}
     
        	// corps du fils
        	else{
          	// On n'a plus besoin du socket en mode écoute :
          	//close(sfd);
     
          	// Fonction recv : permet de recevoir des données du socket de
          	//                 l'arg 1
          	// arg 1 : socket renvoyée par la fonction accept, ici "csfd"
          	// arg 2 : pointeur vers le buffer dans lequel les données transmises
          	//         seront écrites
          	// arg 3 : nombre mamximum d'octets à lire depuis la socket
          	// arg 4 : flags (voir la page man pour plus de détails). 
          	//         Nous mettrons les flags à 0 (aucun flag)
          	//         Rappel sur l'utilisation des flags : 
          	//             Il faut utiliser l'opérateur '|' entre les flags pour
          	//             pouvoir les combiner
     
          	// Cette première utilisation de recv va nous permettre de récupérer 
          	// la taille du nom du fi
          	// chier, ensuite nous recevrons le nom
         	//memset(&participant, 0, sizeof(participant)); 
          	if(recv(csfd, &participant, sizeof(Participant), 0) == -1)
    		{
    			perror("recv");
    			close(csfd);
    			return 6;
          	}
     
            int n;
         	n=strlen(participant.pseudo);
         	write(0, participant.pseudo, n-1); 
         	//printf("%s\n", participant.pseudo);
         	//printf("%s\n", participant.motpasse);
         	//printf("%d\n", participant.point);
         	printf("\n");
     
         	//la fonction lance la communication avec le serveur
         	//d'authentification, elle renvoie un int qui conrrespond à la
         	//réponse du serveur d'auth
         	int resultauth=authentification(participant,ip);
     
         	//on envoie la valeur de resultauth au socket client qui chargera
         	//l'interface adéquate
         	if(send(csfd, &resultauth, sizeof(int), 0) == -1) 
    		{
    		    perror("seendtoclient");
    		    return 7;
    		}
     
         	printf("resultat envoyes serveurs client\n");
     
    		Partie partie;     
     
    		if (resultauth==1) 
    		{
    			semop(semid, &op, 1);
    			memset(&partie, 0, sizeof(Partie));	
         		//Reception de la partie crée par le GM
         		if(recv(csfd, &partie, sizeof(Partie), 0) == -1) 
    			{
         			perror("recvpartie");
       				return 6;
         		}
     
    			printf("Réception des informations partie\n");
     
    			strcpy(mem_partagee.nom_partie, partie.nom);
    			mem_partagee.nb_participants=partie.participants;
    			mem_partagee.taille=(int)partie.taille;
     
    			//on crée le tableau
    			mem_partagee.partie=creer_tableau(partie.taille);
    			mem_partagee.nb_part_jeu=0;
     
    			//on enregistre ces changements dans la
    			//structure
    			*((Mem_partagee*)ptr_mem_partagee) = mem_partagee;
     
    			printf("nom de la partie : %s\n", ((Mem_partagee *)ptr_mem_partagee)->nom_partie);
    			printf("nombre de participants : %d\n", ((Mem_partagee*)ptr_mem_partagee)->nb_participants);
    			printf("Memoire partagee modifiee\n");
    			printf("la taille de la partie : %d\n", partie.taille);
    			printf("nombre de participants en jeu : %d\n", ((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu);
     
    			//on envoie au GM la cle de la mémoire
    			if(send(csfd, &mem_ID, sizeof(int), 0) == -1)
    			{
    				perror("sendcle");
    				return 10;
    			}
    			printf("clef envoe\n");
     
    			semop(semid, &opp, 1);
    		}
     
    		if(resultauth == 0) 
    		{	
     
    			int reponse;
     
    			reponse=accepter_joueur(participant, ip);
     
    			if(send(csfd, &reponse, sizeof(reponse),0) == -1)			
    			{
    				perror("sendreponsetoclient");
    				return 11;
    			}
     
    			printf("envoie de la réponse\n");	
     
    			if(reponse == 1) 
    			{
    				semop(semid, &op, 1);
     
    				printf("nombre de participants : %d\n", ((Mem_partagee*)ptr_mem_partagee)->nb_participants);
    				printf("nom de la partie : %s\n", ((Mem_partagee*)ptr_mem_partagee)->nom_partie);
    				printf("%d", ((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu);
    				((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu=((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu + 1;
    				printf("%d\n", ((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu);
    				//mettre un sémaphore ici
    				((Mem_partagee*)ptr_mem_partagee)->participant[(((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu)-1]=participant;
     
    				printf("participant %s ajoutée à la mémoire partagée\n", 
    				((Mem_partagee*)ptr_mem_partagee)->participant[(((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu)-1].pseudo);
    				semop(semid, &opp, 1);
     
    			while((((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu) != ((Mem_partagee*)ptr_mem_partagee)->nb_participants) 
    			{	
    			int y=0; 
    			y++;	
    			}
     
    			printf("\n");
    			int taille=((Mem_partagee*)ptr_mem_partagee)->taille;
    			printf("la\n");
    			//int taille=debut_partie(ip);
    		 	if(send(csfd, &taille, sizeof(int), 0) == -1) {perror("sendclienttaille"); return 14;}
     
     
    			affiche_partie(((Mem_partagee*)ptr_mem_partagee)->partie, taille);
    			//semop(semid, &op, 1);
    			while(1) 
    			{
    			//on alloue le partie
     
    				semop(semid, &op, 1);
    				affiche_partie(((Mem_partagee*)ptr_mem_partagee)->partie, taille);
    				int l=0, c=0;
     
    				if(recv(csfd, &l, sizeof(int), 0) == -1 || recv(csfd, &c, sizeof(int), 0) ==-1) 
    				{
    					perror("recept coord");
    					return 13;
    				}
     
    				//int**partie;
    				//partie=creer_tableau(taille);
    				//partie=puissance5(partie, taille, l,c);	
    				((Mem_partagee*)ptr_mem_partagee)->partie=puissance5(((Mem_partagee*)ptr_mem_partagee)->partie, taille,l, c);
     
    				printf("partie enregistrée");
    				//partie=mem_partagee.partie;
    				affiche_partie(((Mem_partagee*)ptr_mem_partagee)->partie, taille);
    	        	//affiche_partie(mem_partagee.partie, taille);
    				printf("\n");	
    				//*((Mem_partagee*)ptr_mem_partagee)=mem_partagee;
    				semop(semid, &opp, 1);
     
    				if(send(csfd, &((Mem_partagee*)ptr_mem_partagee)->partie, sizeof(((Mem_partagee*)ptr_mem_partagee)->partie), 0) ==-1) 
    				{
    					perror("Envoi partie");
    					return 14;
    				}
     
    				printf("partie envoyée\n");
    				//envoi_partie(partie,ip);
    			}
     
    		}
        }
        }
    } 
     
      return 0;
    }

  2. #2
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Salut,

    Bon tout d'abord plusieurs petites choses :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Participant participant;
    memset(&participant, 0, sizeof(participant));
     participant=interface();
    Je ne pense pas que ça soit correct, si tu veux initialiser participant via interface, la syntaxe est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    interface(&participant) ;
    // Et l'en-tête de interface :
    void interface(Participant* p) {
    // fonction
    }
    Tu fais peut-être l'erreur à d'autres endroits ce qui pourrait éventuellement être à la source de ta segfault.
    Pour trouver ta segfault facilement tu peux utiliser le logiciel dont je parle ici : http://www.developpez.net/forums/d11...t/#post6138714

    Puis tu rediriges souvent du texte (qui n'est pas du debug) sur stderr qui est la sortie d'erreur, ce qui me semble inapproprié.

    Pour résoudre des problèmes d'accès concurrent à la mémoire, le "mieux" c'est d'utiliser des mutex (mutual exclusion - ils sont un sous-ensemble des sémaphores si on veut).

    Au lieu d'utiliser des processus (je pense que tu utilises un processus par client ?) tu devrais te pencher sur l'utilisation des threads (si tu as le temps).

    Pour les threads et les mutex, je te conseille d'utiliser la norme POSIX (toi tu utilises les sémaphores System-V) qui est portable.

    Tu trouveras un tutoriel ici : http://franckh.developpez.com/tutoriels/posix/pthreads/

    Je pense que tu te compliques la vie en utilisant shmat, de plus ton code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    	Mem_partagee mem_partagee;
    	int mem_ID;
    	memset(&mem_partagee, 0, sizeof(mem_partagee));
     
    //...
     
    if((ptr_mem_partagee = shmat(mem_ID, NULL, 0)) == (void *) -1) 
    	{
    		perror("shmat");
    		return 9;
    	}
     
    	*((Mem_partagee*)ptr_mem_partagee) = mem_partagee;
    ne me semble pas justifié (et la dernière affectation suspecte), tu pourrais simplement utiliser un pointeur et puis c'est tout, ce qui donnerais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Mem_partagee* mem_partagee ;
    if((mem_partagee = shmat(mem_ID, NULL, 0)) == (void *) -1) 
    	{
    		perror("shmat");
    		return 9;
    	}
    Ensuite n'hésite pas à donner des noms plus explicites à tes types (je pense particulièrement à "memoire_partagee", qui un peu comme déclarer un variable avec le nom "var"). Et aussi scinde ton programme en fonction (encore plus) pour avoir des "modules" d'initialisation et de destruction.

    Bonne chance pour ton projet et j'espère que tu trouveras facilement ta segfault

  3. #3
    Candidat au Club
    Homme Profil pro
    elève-ingénieur
    Inscrit en
    Juillet 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : elève-ingénieur

    Informations forums :
    Inscription : Juillet 2011
    Messages : 8
    Points : 2
    Points
    2
    Par défaut
    Merci pour ta réponse et la précision de ta réponse.

    Par rapport à l'utilisation des threads, en fait lors de l'exercice l'emploi des processus était imposé. Et j'aimerais le finir si possible avec les processus et pourquoi pas ensuite le refaire avec les threads.

    J'aimerais savoir si je manipule correctement les sémaphores, même si je n'utilise pas les mutex.

    J'ai bien lu tes remarques et je vais essayer d'en tenir compte au maximum.

    je pars à la recherche de la segfault.

  4. #4
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Je vais prendre un exemple dans ton code, tout le code qui suit est une section critique (c'est-à-dire que un seul processus peut y accéder à un moment t).

    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
    			semop(semid, &op, 1);
    			memset(&partie, 0, sizeof(Partie));	
         		//Reception de la partie crée par le GM
         		if(recv(csfd, &partie, sizeof(Partie), 0) == -1) 
    			{
         			perror("recvpartie");
       				return 6;
         		}
     
    			printf("Réception des informations partie\n");
     
    			strcpy(mem_partagee.nom_partie, partie.nom);
    			mem_partagee.nb_participants=partie.participants;
    			mem_partagee.taille=(int)partie.taille;
     
    			//on crée le tableau
    			mem_partagee.partie=creer_tableau(partie.taille);
    			mem_partagee.nb_part_jeu=0;
     
    			//on enregistre ces changements dans la
    			//structure
    			*((Mem_partagee*)ptr_mem_partagee) = mem_partagee;
     
    			printf("nom de la partie : %s\n", ((Mem_partagee *)ptr_mem_partagee)->nom_partie);
    			printf("nombre de participants : %d\n", ((Mem_partagee*)ptr_mem_partagee)->nb_participants);
    			printf("Memoire partagee modifiee\n");
    			printf("la taille de la partie : %d\n", partie.taille);
    			printf("nombre de participants en jeu : %d\n", ((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu);
     
    			//on envoie au GM la cle de la mémoire
    			if(send(csfd, &mem_ID, sizeof(int), 0) == -1)
    			{
    				perror("sendcle");
    				return 10;
    			}
    			printf("clef envoe\n");
     
    			semop(semid, &opp, 1);
    Normalement tu dois te débrouiller pour que la section critique soit la plus petite possible, hors ici c'est une catastrophe vu que tu as des opérations bloquantes dans cette section critique.

    En plus, c'est quand même bizarre que ça soit le serveur qui doit demander à un client (le GM) la partie ! Normalement c'est le serveur qui connait la partie et qui envoie les informations aux clients. Ce qu'il faudrait c'est juste identifier le GM et lui donner des droits supplémentaires côté serveur.

    Et puis ton recv dans la section critique, maintenant imagine que tu entres dans cette section critique mais que le GM ait crashé son pc ou ait simplement quitté.. Ben t'es deadlock, tu pourras toujours attendre ta partie (note bien que je me demande si le recv ne renvoie pas une erreur lorsque la connexion est perdue, de toutes façons tu dois le gérer).. Et tout les autres processus clients qui se connecterons plus tard attendrons éternellement devant leur P()..

    Pour ce qui est de l'utilisation des threads et mutex, je n'ai rien dit Tu les verras surement plus tard.

  5. #5
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    434
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 434
    Points : 654
    Points
    654
    Par défaut
    Bonjour,
    Pourquoi tu ne regarde pas du coté de select comme ça tu a une gestion réseau non bloquante.
    Et tu n'a pas besoin de faire des threads, enfin après ca dépend du nombres de clients que tu compte avoir sur ton serveur mais tu a le temps de voir venir et le plus avec select tu juste a faire un fork ou un thread pour ajouter des clients sur un autres port.
    Donc plus de semaphore et une gestion un peu plus simple.
    man SELECT(2)

  6. #6
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Es-tu sûr de ce que tu dis ? Je m'explique :

    Tu as le UN descripteur de fichier pour le serveur, le socket serveur qui attend des connexions.

    Donc tu ouvres des autres descripteurs de fichiers pour chaque clients. C'est à ce moment là que tu voudrais utiliser le select ?

    Mais je pense que tu retombes alors dans une programmation séquentielle car comment gérer globalement ces descripteurs de fichiers alors que tu as fait un fork par descripteur qui le gère personnellement ?

    Je dois être passé à côté de quelque chose mais j'aimerais comprendre, merci

  7. #7
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    434
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 434
    Points : 654
    Points
    654
    Par défaut
    Non ton select tu le met au niveau d'une boucle avec x clients.

    Ensuite tu met un limite de client type a partir de 25 clients je fork ou je thread.
    Comme ca tu facilite le fonctionnement de ton serveurs.
    C'est le fonctionnement de beaucoup de serveur.

    L'avantages du select c'est d'avoir plusieurs clients dans la même boucle et tournés sans avoir a ce soucier des blocages sur les send et les recv.

  8. #8
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    J'ai compris mais donc c'est bien du séquentiel...

    Et je trouve ça moche pour un jeu à but pédagogique comme le sien.

    D'autant plus, pourquoi ne pas utiliser un pool de threads au lieu d'une solution comme ça.

    Enfin je veux bien te croire quand tu dis que c'est le fonctionnement de beaucoup de serveurs, ça doit largement alléger la charge.

    Merci pour cette découverte

  9. #9
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    434
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 434
    Points : 654
    Points
    654
    Par défaut
    Bah si tu veux tes sockets c'est des fd.
    Donc ta gestion est beaucoup plus propre comme cela plutôt que venir découpé ton processus.

    En plus c'est moins chiant a débugger, plus robustes, plus de clients sur le serveur.
    Et tu as la protection contre les fonction bloquante.

    En plus pas d'accès concurrentiel au niveau de la mémoires.

    Et les threads, semaphores ou autres tu peux les ajoutés par la suite pour augmenté la charge de ton serveur.

    Tu perd peu être un peu sur l’exécution vu que tu n'envoie pas des messages en simultanés, mais les autres points sont plus intéressant.

  10. #10
    Candidat au Club
    Homme Profil pro
    elève-ingénieur
    Inscrit en
    Juillet 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : elève-ingénieur

    Informations forums :
    Inscription : Juillet 2011
    Messages : 8
    Points : 2
    Points
    2
    Par défaut
    Citation Envoyé par Trademark Voir le message
    En plus, c'est quand même bizarre que ça soit le serveur qui doit demander à un client (le GM) la partie ! Normalement c'est le serveur qui connait la partie et qui envoie les informations aux clients. Ce qu'il faudrait c'est juste identifier le GM et lui donner des droits supplémentaires côté serveur.

    Et puis ton recv dans la section critique, maintenant imagine que tu entres dans cette section critique mais que le GM ait crashé son pc ou ait simplement quitté.. Ben t'es deadlock, tu pourras toujours attendre ta partie (note bien que je me demande si le recv ne renvoie pas une erreur lorsque la connexion est perdue, de toutes façons tu dois le gérer).. Et tout les autres processus clients qui se connecterons plus tard attendrons éternellement devant leur P()..
    Je ne fais que suivre le cahier des charges qui nous était imposé. C'est le Gm après s'être authentifié qui crée la partie. Elle n'existe pas au préalable.

    Pour la section critique, j'ai compris l'idée la réduire au maximum.

    Jouana : Merci pour ton intervention, je vais voir du côté du select, mais avant de vouloir modifier la structure du code, est-ce qu'il y aurait une mauvaise utilisation de la mémoire partagée et des sémaphores, notemment après le début de la partie

    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
    if(resultauth == 0) 
    		{	
     
    			int reponse;
     
    			reponse=accepter_joueur(participant, ip);
     
    			if(send(csfd, &reponse, sizeof(reponse),0) == -1)			
    			{
    				perror("sendreponsetoclient");
    				return 11;
    			}
     
    			printf("envoie de la réponse\n");	
     
    			if(reponse == 1) 
    			{
    				semop(semid, &op, 1);
     
    				printf("nombre de participants : %d\n", ((Mem_partagee*)ptr_mem_partagee)->nb_participants);
    				printf("nom de la partie : %s\n", ((Mem_partagee*)ptr_mem_partagee)->nom_partie);
    				printf("%d", ((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu);
    				((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu=((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu + 1;
    				printf("%d\n", ((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu);
    				//mettre un sémaphore ici
    				((Mem_partagee*)ptr_mem_partagee)->participant[(((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu)-1]=participant;
     
    				printf("participant %s ajoutée à la mémoire partagée\n", 
    				((Mem_partagee*)ptr_mem_partagee)->participant[(((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu)-1].pseudo);
    				semop(semid, &opp, 1);
     
    			while((((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu) != ((Mem_partagee*)ptr_mem_partagee)->nb_participants) 
    			{	
    			int y=0; 
    			y++;	
    			}
     
    			printf("\n");
    			int taille=((Mem_partagee*)ptr_mem_partagee)->taille;
    			printf("la\n");
    			//int taille=debut_partie(ip);
    		 	if(send(csfd, &taille, sizeof(int), 0) == -1) {perror("sendclienttaille"); return 14;}
     
     
    			affiche_partie(((Mem_partagee*)ptr_mem_partagee)->partie, taille);
    			//semop(semid, &op, 1);
    			while(1) 
    			{
    			//on alloue le partie
     
    				semop(semid, &op, 1);
    				affiche_partie(((Mem_partagee*)ptr_mem_partagee)->partie, taille);
    				int l=0, c=0;
     
    				if(recv(csfd, &l, sizeof(int), 0) == -1 || recv(csfd, &c, sizeof(int), 0) ==-1) 
    				{
    					perror("recept coord");
    					return 13;
    				}
     
    				//int**partie;
    				//partie=creer_tableau(taille);
    				//partie=puissance5(partie, taille, l,c);	
    				((Mem_partagee*)ptr_mem_partagee)->partie=puissance5(((Mem_partagee*)ptr_mem_partagee)->partie, taille,l, c);
     
    				printf("partie enregistrée");
    				//partie=mem_partagee.partie;
    				affiche_partie(((Mem_partagee*)ptr_mem_partagee)->partie, taille);
    	        	//affiche_partie(mem_partagee.partie, taille);
    				printf("\n");	
    				//*((Mem_partagee*)ptr_mem_partagee)=mem_partagee;
    				semop(semid, &opp, 1);
     
    				if(send(csfd, &((Mem_partagee*)ptr_mem_partagee)->partie, sizeof(((Mem_partagee*)ptr_mem_partagee)->partie), 0) ==-1) 
    				{
    					perror("Envoi partie");
    					return 14;
    				}
     
    				printf("partie envoyée\n");
    				//envoi_partie(partie,ip);
    			}
    Je suis à mon stage, donc je ne me suis pas encore penché sur tous les liens que vous m'avez conseillé mais je le ferai au plus vite.
    Merci d'avance pour le temps.

  11. #11
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    			while((((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu) != ((Mem_partagee*)ptr_mem_partagee)->nb_participants) 
    			{	
    			int y=0; 
    			y++;	
    			}
    Je dirais qu'il y a comme un problème.. Je suppose que tu veux faire un truc comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while((((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu) != ((Mem_partagee*)ptr_mem_partagee)->nb_participants) ;
    Mais c'est très déconseillé vu que c'est une boucle active.. Pour résoudre ce problème tu peux te renseigner sur les moniteurs et tu pourras avoir quelque chose de ce gabarit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SECTION_CRITIQUE_commence() ;
    while((((Mem_partagee*)ptr_mem_partagee)->nb_part_jeu) != ((Mem_partagee*)ptr_mem_partagee)->nb_participants) 
    {
        ATTENDRE() ; // libère la section critique mais ne pourra "re-rentrer" dedans que lorsque cette section critique sera libre.
    }
     
    PREVENIR() ; // Réveil tout ceux qui était en attente.
    SECTION_CRITIQUE_fin() ;

    Sinon au niveau des sémaphores, une fois de plus tes sections critiques sont trop grandes. Par contre, il est indispensable d'utiliser ta sémaphore à chaque modification de la mémoire partagée. Tu peux également protéger les accès en lecture si la cohérence des affichages est importante.

    Mais évite de mettre des opérations d'entrée/sortie dans tes sections critiques c'est ce qui prend le plus de temps (printf, scanf, write, read, ...).

    Sinon pour tes sémaphores, si tu ne sais pas quand les utiliser c'est simple, tu dois avoir une section critique à chaque fois que tu modifies la mémoire partagée. Tu peux également en avoir quand tu lis si la variable que tu lis est sujette à des modifications de la part des autres processus.

  12. #12
    Candidat au Club
    Homme Profil pro
    elève-ingénieur
    Inscrit en
    Juillet 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : elève-ingénieur

    Informations forums :
    Inscription : Juillet 2011
    Messages : 8
    Points : 2
    Points
    2
    Par défaut
    Après avoir pataugé, j'ai trouvé une première bête notamment grâce à l'outil de débugage qui m'a fixé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    if(recv(sfd, &partie, sizeof(partie), 0) == -1) 
    					{
    						perror("erreur partie");
    						return 15;
    		  			}
    c'est bête que je n'y ai pas pensé mais partie est un double pointeur sur int. donc il ne peut pas être envoyé ou reçu de cette manière, il faut nécessairement une boucle, comme pour l'allocation d'un tableau à double pointeur non ?

    Je vais remédier à cela et je vous tiens au courant. J'ai par contre effectué les modifications de syntaxe comme suggéré Trademark

  13. #13
    Candidat au Club
    Homme Profil pro
    elève-ingénieur
    Inscrit en
    Juillet 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : elève-ingénieur

    Informations forums :
    Inscription : Juillet 2011
    Messages : 8
    Points : 2
    Points
    2
    Par défaut
    Suite à ton conseil je rouvre la conversation.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int semid=semget (clef, 2, IPC_CREAT | IPC_EXCL | 0666);
    	semctl(semid, 0, SETVAL, 1);
    	sembuf op;
    	sembuf opp;
     
    	op.sem_num = 0;//numéro de notre sémaphore
    	op.sem_op  = -1;//Pour un P() on décrémente
    	op.sem_flg = 0;
     
    	opp.sem_num = 0;
    	opp.sem_op  = 1;
    	opp.sem_flg = 0;
    Pour utiliser le sémaphores je déclare deux structures op et opp mais n'aurait-il pas fallu qu'en j'en déclare qu'une seule et que je change à chaque fois la valeur de
    pour vérouiller et en pour libérer ?

  14. #14
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    N'oublions pas ce que tu m'as dit plus tôt :

    Mais là, je touche à la partie la plus sensible sur laquelle je suis bloqué depuis quelques temps le tour par tour. De ce que j'avais compris, les sémaphores devaient servir en plus de protéger les accés mémoire, à gérer les processus, mais je me rends compte que non ou alors j'ai fait une mauvaise utilisation.
    [1] Pour ton code, op et opp je ne pense pas que ça veut dire quelque chose de bien précis à part opération. Tu pourrais nommer ça P et V ou prendre et rendre, à ta guise. Ça montrerait bien le rôle de ces variables.
    Ensuite je ne pense pas que ça soit une bonne idée de n'utiliser qu'une structure. Si j'étais toi, je privilégierais la clarté à ce niveau là.

    [2] Pour le tour par tour, c'est assez simple. Tu fais un tableau de sémaphore de N joueurs et puis tu peux utiliser le pseudo-code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Initialiser tableau semaphore S[n] à 0 (sauf le premier joueur à 1). 
     
    P(S[mon_num_joueur]) ; // Attendre son tour
     
    JOUER() ;
     
    V(S[mon_num_joueur + 1 % total_joueur]) ; // Autoriser le joueur suivant.
    Du coup les joueurs joueront chacun à leur tour. Cependant, n'oublie pas de gérer la fin de la partie.

    Dans JOUER(), si il y a des ressources critiques qui ne sont utilisées que là, tu n'es pas obligé de créer une section critique vu qu'il n'y aura à tout moment que joueur entre le P() et le V(). On dit que la synchronisation entre processus règle les problèmes d'exclusions mutuelles. Évidemment si tu utilises des ressources en dehors de ce P et V, section critique obligatoire !!

  15. #15
    Candidat au Club
    Homme Profil pro
    elève-ingénieur
    Inscrit en
    Juillet 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : elève-ingénieur

    Informations forums :
    Inscription : Juillet 2011
    Messages : 8
    Points : 2
    Points
    2
    Par défaut
    Je n'avais pas pensé que l'on pouvait faire des tableaux de sémaphores, merci.

    Je pense que je vais relire 2 3 trucs sur les sémaphores. SI j'ai un soucis...

    Je suis tombé sur un code de ce type. C'est de ce genre d'implémentation dont tu fais allusion ?

    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
     
    key_t cle ;
    int initval ;
    {
    int semid ;
    union semun {
    int val ;
    struct semid_ds *buf ;
    ushort *array ;
    } arg_ctl ;
    semid = semget(ftok("dijkstra.h",cle),1,IPC_CREAT|IPC_EXCL|0666) ;
    if (semid == -1) {
    semid = semget(ftok("dijkstra.h",cle),1, 0666) ;
    if (semid == -1) {
    perror("Erreur semget()") ;
    exit(1) ;
    }
    }
    arg_ctl.val = initval ;
    if (semctl(semid,0,SETVAL,arg_ctl) == -1) {
    perror("Erreur initialisation semaphore") ;
    exit(1) ;
    }
    return(semid) ;
    }
    void P(semid)
    int semid ;
    {
    struct sembuf sempar ;
    sempar.sem_num = 0 ;
    sempar.sem_op = -1 ;
    sempar.sem_flg = SEM_UNDO ;
    if (semop(semid, &sempar, 1) == -1)
    perror("Erreur operation P") ;
    }
    void V(semid)
    int semid ;
    {
    struct sembuf sempar ;
    sempar.sem_num = 0 ;
    sempar.sem_op = 1 ;
    sempar.sem_flg = SEM_UNDO ;
    if (semop(semid, &sempar, 1) == -1)
    perror("Erreur operation V") ;
    }
    void sem_delete(semid)
    int semid ;
    {
    if (semctl(semid,0,IPC_RMID,0) == -1)
    perror("Erreur dans destruction semaphore"); 
     
    }
     
     
     
    //tab de semaphore 
    int tab[5]:
    for (i=0;i<(taille);i++)
    {
    tab[i]= sem_create(i,1) ;
    printf("creation du semaphore s_tab_nc [%d]= %d \n",i,s_tab_nc[i]);
    }

  16. #16
    Candidat au Club
    Homme Profil pro
    elève-ingénieur
    Inscrit en
    Juillet 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : elève-ingénieur

    Informations forums :
    Inscription : Juillet 2011
    Messages : 8
    Points : 2
    Points
    2
    Par défaut
    J'ai essayé ta technique du tableau des sémaphores, alors j'ai bien un semblant de tour par tour qui se met en place, mais lorsque c'est au deuxième joueur de jouer, la partie envoyée n'est pas celle en cours, de plus une fois que le 2e joueur a envoyé ses coordonnées, j'ai une SIGPIPE

    Alors je ne sais vraiment pas d'où vient le problème je suis un peu perdu, est ce que tu pourrais me donner une implémentation pour cette partie ?

    je n'ai mis que les parties ou j'utilise des sémaphores et la boucle contenant la partie en cours.

    Le code côté serveur,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int i;
    	int sem[2];
    	for(i = 0; i < 2; i++)
    	{
    		sem[i] = sem_create(i);
    		printf("creation du semaphore %d\n", sem[i]);
    	}
    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
     
    P(sem[i]);
     
    						int w=0, x=0;
    						for(w=0; w < taille; w++)
    						{
    							for(x=0; x < taille; x++)
    							{
    								if(send(csfd, &((mem_partagee)->partie[w][x]), sizeof(int), 0) == -1) 
    								{
    									perror("Envoi partie");
    									return 14;
    								}
    							}
    						}
    						printf("partie envoyee\n");
     
     
    						int l=0,c=0;
     
    						if(recv(csfd, &l, sizeof(int), 0) == -1 || 
    					       recv(csfd, &c, sizeof(int), 0) == -1) 
    						{
    							perror("recept coord");
    							return 13;
    						}
     
    						(mem_partagee)->partie=puissance5((mem_partagee)->partie, taille,l, c);
     
    						printf("partie enregistree");
    						affiche_partie((mem_partagee)->partie, taille);
    						printf("\n");	
    			/*						int w=0, x=0;
    						for(w=0; w < taille; w++)
    						{
    							for(x=0; x < taille; x++)
    							{
    								op.sem_op = -1;
    								semop(semid, &op, 1);
    								if(send(csfd, &((mem_partagee)->partie[w][x]), sizeof(int), 0) == -1) 
    								{
    									perror("Envoi partie");
    									return 14;
    								}
    								op.sem_op = 1;
    								semop(semid, &op, 1);
    							}
    						}*/
     
    						V(sem[i]);
    						i++;
    						if(i > mem_partagee->nb_part_jeu) i=0;
     
    						//sleep(3);
    côté 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
     
    while(1) 
    				{
    		  			int **partie;
    		  			partie=creer_tableau(i);
     
    					int w=0, x=0;
    					for(w=0; w < i; w++)
    					{
    						for(x=0; x < i; x++)
    						{
    							if(recv(sfd, &(partie[w][x]), sizeof(int), 0) == -1) 
    							{
    								perror("Envoi partie");
    								return 14;
    							}
    						}
    					}
    	  				printf("partie reçue");	
    		 			affiche_partie(partie, i);
     
    		  			int l=0; 
    		  			int c=0;
     
    					do 
    					{
    						printf("La partie est de type %dx%d, Entrez les coordonnées : ", i-1, i-1);
     
    						printf("\n");
    						fprintf(stderr, "Ligne : ");
    		  				scanf("%d", &l);
    		  				fprintf(stderr, "Colonne : "); 
    		  				scanf("%d", &c);
    					} while ((c>(i-1)) | (l>(i-1)));
     
    		  			if(send(sfd, &l, sizeof(int), 0) == -1 || send(sfd, &c, sizeof(int), 0) == -1)
    		  			{
    			  			perror("envoie coord");
    			  			return 14;
    		  			}
     
    		  			printf("Coordonnees envoyees\n");
     
    				}	  
     
    		 	}
    			else 
    			{ 
    				printf("connexion refusée par le gm\n");
    				close(sfd);
    				return 13;
    		  	}
     
    			break;
    c'est le send du client qui pose probléme.

    Merci d'avance, je suis à court d'idée et il y a quelque chose qui m'échappe clairement. (surprenant d'être largué par son propre code :o)

  17. #17
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Dans la doc on peut lire :

    Citation Envoyé par man socket
    Un signal SIGPIPE est envoyé au processus tentant d'écrire sur une socket inutilisable, forçant les programmes ne gérant pas ce signal à se terminer.
    Donc vérifie que ton socket n'est pas fermé entre temps, qu'il est bien créé, ect.

    Et j'ai vu autre chose de dérangeant dans ton code qui peut ammener à un deadlock côté serveur. Quand tu fais tes return 13 ou return 12, ... lorsqu'il y a une erreur, tu dois libérer les ressources ! Donc faire un V(sem...). Vu que tu quittes la section critique. Pour éviter de libérer des ressources partout, et si tu trouves que c'est moins clair tu peux faire de grand if-else et utiliser une variable erreur que tu renvois à la fin du code. Comme ça la ressource est libérée partout au même endroit. Enfin c'est toi qui voit mais le plus important c'est de la libérer !

  18. #18
    Candidat au Club
    Homme Profil pro
    elève-ingénieur
    Inscrit en
    Juillet 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : elève-ingénieur

    Informations forums :
    Inscription : Juillet 2011
    Messages : 8
    Points : 2
    Points
    2
    Par défaut
    pour les return, j'ai modifié, par contre je ne comprends toujours pas pourquoi j'ai une SIGEPIPE, la scocket est toujours ouverte et fonctionnel, en fait le 1er Joueur à jouer continue à jouer mais seul.

    Donc là je pourrais comprendre SIGPIPE, parce que le premier processus ne laissant jamais la place au second, au moment où le second souhaite communiquer avec le serveur il reçoit une erreur, mais normalement puisque le serveur est toujours ouvert, ne devrait il pas attendre jusqu'à le serveur soit libéré ?

    Je suis vraiment perdu :s

  19. #19
    Inactif
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    30
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2011
    Messages : 30
    Points : 8
    Points
    8
    Par défaut
    Je poste pour suivre :-S Intéressent le réseau

Discussions similaires

  1. récupérer string par socket TCP
    Par bogsy15 dans le forum C++
    Réponses: 14
    Dernier message: 11/06/2006, 16h05
  2. socket TCP
    Par fxp17 dans le forum C++
    Réponses: 6
    Dernier message: 28/11/2005, 09h55
  3. [SOCKET] TCP : select devant send();
    Par trois_1 dans le forum Développement
    Réponses: 4
    Dernier message: 02/03/2004, 18h10
  4. [socket][tcp] jeu en reseau
    Par souris_sonic dans le forum Développement
    Réponses: 2
    Dernier message: 30/05/2003, 07h31
  5. transfert d'un fichier bitmap en socket tcp
    Par localhost dans le forum C++Builder
    Réponses: 5
    Dernier message: 29/07/2002, 00h40

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