[C++] Communication entre 2 threads
Fermé
NicoBoklo
Messages postés
87
Date d'inscription
samedi 2 décembre 2006
Statut
Membre
Dernière intervention
8 septembre 2010
-
7 avril 2008 à 23:15
sweety - 2 févr. 2012 à 23:14
sweety - 2 févr. 2012 à 23:14
A voir également:
- [C++] Communication entre 2 threads
- 2 ecran pc - Guide
- Word numéro de page 1/2 - Guide
- 3 bip long 2 bip court hp - Forum BIOS
- Xsarius pure 2 mode d'emploi - Forum TV & Vidéo
- France 2 uhd - Accueil - TV & Vidéo
12 réponses
NicoBoklo
Messages postés
87
Date d'inscription
samedi 2 décembre 2006
Statut
Membre
Dernière intervention
8 septembre 2010
2
8 avril 2008 à 09:43
8 avril 2008 à 09:43
Salut à tous les 2...
En gros vos solutions se ressemblent mais le problème est bien le "lui" dans envoi "ça" à "lui". Je pense que jusque là on est tous d'accord. Si je comprends bien, le mieux à faire sa serai un truc du genre :
- faire une liste des nom de clients avec socket associé.
- le client1 envoi au serveur le nom du destinataire et le message
- le serveur regarde la liste des client et deduit le socket
- send au destinataire grâce au socket trouver...
sinon :
- faire une liste des nom de client avec indentifiant du thread asocié
- le client1 regarde la liste et trouve l'identifiant du thread du destinataire
- ensuite communication entre thread
En gors j'vois que ces 2 solutions (Z'êtes d'accord avec moi? ^^)
Maintenant ce qui m'enerver (et oui sa m'arrive) c'est que j'ai pomper ce code sur le net (sans vraiment comprendre le principe du thread) Du coup la partie création de serveur no problems! Quand j'attaque la partie thread (aille), c'est finis. Du coup, la solution ou j'ai tendance à plus pencher, utiliser les sockets (et leur descripteur de flux). Je vais faire une chose plus simple, voila le code source : (au moins les idées serons plus claires)
Serveur.cpp :
Voilà, je passe le main pas très utile et d'autre fonction (du genre serveur::pause()).
En gros ce qu'il me faut, pouvoir récupérer soit l'identifiant du thread lors de sa création, soit obtenir le socket créer (SOCKET soc en paramètre dans ClientThread) Première solution, je ne sais pas comment faire pour obtenir l'identifiant d'un thread. 2ème solution, je stock le socket client (dans un tableau 2D par exemple tab[pseudo][SOCKET]) du coup je me retrouve avec ma liste des clients.
Ensuite, le clients envoi le pseudo à qui il veut parler au serveur, le serveur lit dans le tableau, trouve le socket et fait un send avec le bon socket.
Désolé si c'est pas très clair ce que je dis... J'ai dû me reprendre à 2 fois mais c'est tellement flou tout sa...
Merci de votre patiente.
En gros vos solutions se ressemblent mais le problème est bien le "lui" dans envoi "ça" à "lui". Je pense que jusque là on est tous d'accord. Si je comprends bien, le mieux à faire sa serai un truc du genre :
- faire une liste des nom de clients avec socket associé.
- le client1 envoi au serveur le nom du destinataire et le message
- le serveur regarde la liste des client et deduit le socket
- send au destinataire grâce au socket trouver...
sinon :
- faire une liste des nom de client avec indentifiant du thread asocié
- le client1 regarde la liste et trouve l'identifiant du thread du destinataire
- ensuite communication entre thread
En gors j'vois que ces 2 solutions (Z'êtes d'accord avec moi? ^^)
Maintenant ce qui m'enerver (et oui sa m'arrive) c'est que j'ai pomper ce code sur le net (sans vraiment comprendre le principe du thread) Du coup la partie création de serveur no problems! Quand j'attaque la partie thread (aille), c'est finis. Du coup, la solution ou j'ai tendance à plus pencher, utiliser les sockets (et leur descripteur de flux). Je vais faire une chose plus simple, voila le code source : (au moins les idées serons plus claires)
Serveur.cpp :
int serveur::start (){
SOCKADDR_IN ClientAddr;
int ClientAddrLen;
HANDLE hProcessThread;
SOCKET NewConnection;
struct thread_param p;
if( ( ListeningSocket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ){
cerr << "ne peut creer la socket. Erreur no " << WSAGetLastError()<< endl;
WSACleanup();
return 1;
}
if( bind( ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof( ServerAddr ) ) == SOCKET_ERROR ){
cerr << "bind a echoue avec l'erreur " << WSAGetLastError() << endl;
cerr << "Le port est peut-etre déja utilise par un autre processus " << endl;
closesocket( ListeningSocket );
WSACleanup();
return 1;
}
if( listen( ListeningSocket, 5 ) == SOCKET_ERROR ){
cerr << "listen a echoue avec l'erreur " << WSAGetLastError() << endl;
closesocket( ListeningSocket );
WSACleanup();
return 1;
}
cout << "serveur demarre : a l'ecoute du port " << port << endl;
running = true;
ClientAddrLen = sizeof( ClientAddr );
while(running){
if((NewConnection = accept( ListeningSocket, (SOCKADDR *) &ClientAddr, &ClientAddrLen)) == INVALID_SOCKET){
cerr << "accept a echoue avec l'erreur " << WSAGetLastError() << endl;;
closesocket( ListeningSocket );
WSACleanup();
return 1;
}
p.ser = this;
p.soc = NewConnection;
cout << "client connecte :: IP : " <<inet_ntoa( ClientAddr.sin_addr )<< " ,port = " <<ntohs( ClientAddr.sin_port ) << endl;
hProcessThread = CreateThread(NULL, 0,&serveur::ThreadLauncher, &p,0,NULL);
if ( hProcessThread == NULL ){
cerr << "CreateThread a echoue avec l'erreur " <<GetLastError()<< endl;
}
}
return 0;
}
/* Thread client */
DWORD serveur::ClientThread(SOCKET soc){
/*==========Code client===========*/
}
Serveur.h :
<code>#ifndef __serveur_h__
#define __serveur_h__
#include <winsock2.h>
class serveur;
struct thread_param{
serveur* ser;
SOCKET soc;
};
class serveur{
private:
int port;
SOCKET ListeningSocket;
bool running;
SOCKADDR_IN ServerAddr;
DWORD ClientThread(SOCKET);
public:
serveur(int);
int init();
int start ();
int pause ();
static DWORD WINAPI ThreadLauncher(void *p){
struct thread_param *Obj = reinterpret_cast<struct thread_param*>(p);
serveur *s = Obj->ser;
return s->ClientThread(Obj->soc);
}
};
#endif
Voilà, je passe le main pas très utile et d'autre fonction (du genre serveur::pause()).
En gros ce qu'il me faut, pouvoir récupérer soit l'identifiant du thread lors de sa création, soit obtenir le socket créer (SOCKET soc en paramètre dans ClientThread) Première solution, je ne sais pas comment faire pour obtenir l'identifiant d'un thread. 2ème solution, je stock le socket client (dans un tableau 2D par exemple tab[pseudo][SOCKET]) du coup je me retrouve avec ma liste des clients.
Ensuite, le clients envoi le pseudo à qui il veut parler au serveur, le serveur lit dans le tableau, trouve le socket et fait un send avec le bon socket.
Désolé si c'est pas très clair ce que je dis... J'ai dû me reprendre à 2 fois mais c'est tellement flou tout sa...
Merci de votre patiente.
tatou_38
Messages postés
1928
Date d'inscription
vendredi 21 avril 2006
Statut
Membre
Dernière intervention
5 août 2015
121
7 avril 2008 à 23:20
7 avril 2008 à 23:20
Que tu ne puisse communiquer entre deux clients c'est normal. Les deux clients ne peuvent communiquer entr'eux qu'au travers du serveur s'il est prévu pour et l'accepte.
Communiquer entre deux threads est simple, vu que tous les threads ont la mémoire de l'application en commun. Mais atention, il faut desfois protéger les accès pour éviter des effets de bords aléatoires et difficiles à dénicher.
Communiquer entre deux threads est simple, vu que tous les threads ont la mémoire de l'application en commun. Mais atention, il faut desfois protéger les accès pour éviter des effets de bords aléatoires et difficiles à dénicher.
NicoBoklo
Messages postés
87
Date d'inscription
samedi 2 décembre 2006
Statut
Membre
Dernière intervention
8 septembre 2010
2
7 avril 2008 à 23:54
7 avril 2008 à 23:54
Merci pour ta réponse aussi rapide!
Donc en gros si je comprends bien :
Client1 dit au serveur : dit "salut" à Client2.
En gros ce qu'il faut c'est :
- le client 1 envoi au serveur le message plus le destinataire.
- le serveur envoi au client 2 le message avec le nom de l'expediteur.
Concretement je code celà :
Client1:
Serveur :
Ben la je bloque... Si je fait un send(...) j'envoi les infos directement à tous les clients (si je me trompe pas...) Comment doit-je faire pour dire envoi "ça" à "lui". Il faut déjà differencier les 2 clients (identifiant de leur thread?) et ensuite envoyer le message au bon destinataire (une fonction spécifique à sa?...)
Aussi pour mieux comprendre l'utilité d'un thread. fork equivalent à thread sauf sans le pipe (à cause de la mémoire partagée?)
Du coup sa serai peut-être plus simple de faire ça à coup de fork...
Un client se connecte, je "fork", s'il veut parler à un autre client je fais un pipe entre les 2 processus... Après la communication c'est du gateau! Mais sous winwin y'a un équivalent à sa...
Merci de ton aide.
Donc en gros si je comprends bien :
Client1 dit au serveur : dit "salut" à Client2.
En gros ce qu'il faut c'est :
- le client 1 envoi au serveur le message plus le destinataire.
- le serveur envoi au client 2 le message avec le nom de l'expediteur.
Concretement je code celà :
Client1:
cout<<"Entrer le destinataire : "; cin>>destinataire; send(socket,destinataire,sizeof(destinaire),0); cout<<"Entrer votre message : "; cin>>message; send(socket,message,sizeof(message),0);
Serveur :
recv(socket,destinataire,sizeof(destinataire),0); recv(socket,message,sizeof(message),0); et ensuite...
Ben la je bloque... Si je fait un send(...) j'envoi les infos directement à tous les clients (si je me trompe pas...) Comment doit-je faire pour dire envoi "ça" à "lui". Il faut déjà differencier les 2 clients (identifiant de leur thread?) et ensuite envoyer le message au bon destinataire (une fonction spécifique à sa?...)
Aussi pour mieux comprendre l'utilité d'un thread. fork equivalent à thread sauf sans le pipe (à cause de la mémoire partagée?)
Du coup sa serai peut-être plus simple de faire ça à coup de fork...
Un client se connecte, je "fork", s'il veut parler à un autre client je fais un pipe entre les 2 processus... Après la communication c'est du gateau! Mais sous winwin y'a un équivalent à sa...
Merci de ton aide.
tatou_38
Messages postés
1928
Date d'inscription
vendredi 21 avril 2006
Statut
Membre
Dernière intervention
5 août 2015
121
8 avril 2008 à 08:23
8 avril 2008 à 08:23
Normalement le dialogue est sur initiative du client : le client envoie une question au serveur qui lui répond.
Là tu veux que le serveur envoie un message à un client précis sans que ce soit une réponse. Donc il faut que le serveur sache quel est le socket à utiliser pour faire le send.
Logiquement, le serveur crée un thread à chaque connexion, chaque thread correspond donc à un client. Il faut donc (par exemple) que tu demande au bon thread d'envoyer la sauce.
D'autre part, il faut que le client soit conçu pour traiter des messages "non sollicités", c'est à dire qui arrivent à n'importe quel moment sans être une réponse à une question.
Là tu veux que le serveur envoie un message à un client précis sans que ce soit une réponse. Donc il faut que le serveur sache quel est le socket à utiliser pour faire le send.
Logiquement, le serveur crée un thread à chaque connexion, chaque thread correspond donc à un client. Il faut donc (par exemple) que tu demande au bon thread d'envoyer la sauce.
D'autre part, il faut que le client soit conçu pour traiter des messages "non sollicités", c'est à dire qui arrivent à n'importe quel moment sans être une réponse à une question.
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Char Snipeur
Messages postés
9813
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
3 octobre 2023
1 298
8 avril 2008 à 08:54
8 avril 2008 à 08:54
Salut, pas du tout d'accord avec tatou.
En client serveur, une fois la connexion établi, on peux dire qu'il n'y a plus de client et de serveur. tu peux faire des send ou recv dans le sens que tu veux, attention tout de même à les enchainer correctement pour faire la même chose du coté serveur que du coté client.
lorsque tu fait un send depuis le serveur, tu ne l'envoie pas à tout les clients, il suffit de spécifier le socket du client à qui tu veux l'envoyer. Lorsque tu fait socketC=accept(...) socketC est un descripteur de flux réseau vers le client qui viens de se connecter. il suffit alors de tout copier en passant ça à un thread.
Pour les thead, j'utilise pthead, qui est bien documenter sur Linux et disponible sous windows. Je le trouve relativment simple d'utilisation.
Ensuite, il faut faire la communication entre thread.
Je te cache pas qu'un point délicat c'est de savoir vers qui le serveur doit retourner le message depuis ce qu'il reçoit de son client.
En client serveur, une fois la connexion établi, on peux dire qu'il n'y a plus de client et de serveur. tu peux faire des send ou recv dans le sens que tu veux, attention tout de même à les enchainer correctement pour faire la même chose du coté serveur que du coté client.
lorsque tu fait un send depuis le serveur, tu ne l'envoie pas à tout les clients, il suffit de spécifier le socket du client à qui tu veux l'envoyer. Lorsque tu fait socketC=accept(...) socketC est un descripteur de flux réseau vers le client qui viens de se connecter. il suffit alors de tout copier en passant ça à un thread.
Pour les thead, j'utilise pthead, qui est bien documenter sur Linux et disponible sous windows. Je le trouve relativment simple d'utilisation.
Ensuite, il faut faire la communication entre thread.
Je te cache pas qu'un point délicat c'est de savoir vers qui le serveur doit retourner le message depuis ce qu'il reçoit de son client.
Char Snipeur
Messages postés
9813
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
3 octobre 2023
1 298
8 avril 2008 à 10:48
8 avril 2008 à 10:48
hProcessThread est ton identificateur de thread.
il te reste alors à le récupérer et à l'associer avec le socket et l'ip qui vont avec dans une variable.
Je pense que tu peux utilisé maps de la STL pour ça.
Ensuite, lorsque chaque thread créé reçoit un nouveau message, il faut qu'il le renvoie au bon destinataire.
https://docs.microsoft.com/en-us/previous-versions/bb202727(v=msdn.10)?redirectedfrom=MSDN
il te reste alors à le récupérer et à l'associer avec le socket et l'ip qui vont avec dans une variable.
Je pense que tu peux utilisé maps de la STL pour ça.
Ensuite, lorsque chaque thread créé reçoit un nouveau message, il faut qu'il le renvoie au bon destinataire.
https://docs.microsoft.com/en-us/previous-versions/bb202727(v=msdn.10)?redirectedfrom=MSDN
NicoBoklo
Messages postés
87
Date d'inscription
samedi 2 décembre 2006
Statut
Membre
Dernière intervention
8 septembre 2010
2
8 avril 2008 à 11:08
8 avril 2008 à 11:08
En fait je viens de trouver une petite solution. Je vais déjà tenter de faire simple. Le serveur est senser être utile dans un jeu de poker. Du coup aucun problème pour les recv() et send() entre serveur et client puisque je connais déjà l'ordre des receptions/envois. En gros ce que je fait, je créer un tableau 2D (10 entrées) dans serveur.cpp. A chaque fois qu'un client se connecte, j'ajoute son socket dans le tableau. Une fois le tableau remplis les connections sont refusées et le jeu est lancer. Le serveur envoi à "joueur" ses cartes (je lis dans le tableau le socket du joueur) et j'utilise le socket obtenu pour faire un send.
Pour le jeu de poker, je pense que cel est plus simple, ensuite pour pouvoir créer un "t'chat", la communication entre thread serait donc mieux. Je vais un peu avancé dans ce petit serveur et vous tiens au courant de l'avancement.
Je pense que ma solution devrait marcher...
En tout cas merci à vos de m'avoir éclairé!
Pour le jeu de poker, je pense que cel est plus simple, ensuite pour pouvoir créer un "t'chat", la communication entre thread serait donc mieux. Je vais un peu avancé dans ce petit serveur et vous tiens au courant de l'avancement.
Je pense que ma solution devrait marcher...
En tout cas merci à vos de m'avoir éclairé!
Char Snipeur
Messages postés
9813
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
3 octobre 2023
1 298
8 avril 2008 à 12:15
8 avril 2008 à 12:15
Le problème du chat, c'est qu'en effet, l'ordre des envoie réception n'est pas connu à l'avance.
je croix que la solution choisi dans ce cas là, c'est de faire deux thread, un pour les messages allant de A à B et un pour ceux allant de à A. Bien entendu, si il faut passer par un serveur, c'est un poil plus compliquer.
je croix que la solution choisi dans ce cas là, c'est de faire deux thread, un pour les messages allant de A à B et un pour ceux allant de à A. Bien entendu, si il faut passer par un serveur, c'est un poil plus compliquer.
NicoBoklo
Messages postés
87
Date d'inscription
samedi 2 décembre 2006
Statut
Membre
Dernière intervention
8 septembre 2010
2
8 avril 2008 à 14:06
8 avril 2008 à 14:06
J'avais aussi penser à ce genre de schéma, en gros un thread d'ecoute et un thread d'envoi. Mais vu mes compétences en thread j'vais abandonner l'idée du "t'chat" pour passer a un schéma connue (mon jeu de poker) Par contre si tu a des liens pour des cours sur les threads il sont les bienvenues, j'en ai chercher mais je n'ai rien trouver, ou en tout cas aucun cours prennant les bases ou expliquant correctement le thread et les paramètre qu'on lui passe lors de la création! Je te remercie pour ton aide, j'ai pas mal avancer et maintenant que je sais communiquer avec un client précis, je vais attaquer la partie graphique de mon jeu, et sa c'est une autre paire de manche!
Char Snipeur
Messages postés
9813
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
3 octobre 2023
1 298
8 avril 2008 à 15:11
8 avril 2008 à 15:11
voici un petit exemple que j'ai construit en pthread.
c'est juste pour tester les thread et les variables qu'ils modifie. Je pense que les fonctions équivalent existent en thread win classique.
c'est juste pour tester les thread et les variables qu'ils modifie. Je pense que les fonctions équivalent existent en thread win classique.
#include <stdio.h> int glabol=1; void* cal(void* x) { static int nn=glabol; for(long int j=-100;j<100;j++) for(int i=0;i<100000;i++) i=i+1944-3*6*9*12; int xi=*(int*)x; xi=xi*xi;printf("dans cal %d nb apel : %d\n",xi,nn); //x=ξ *(int*)x=xi; nn++; glabol=xi;return x; }; void* fonc(void* x); int main() { pthread_t tt,uu; pthread_attr_t *tt_attr,*uu_attr; int k; int*x;int j=10;x=&j; tt_attr =new pthread_attr_t; pthread_attr_init(tt_attr); pthread_attr_setdetachstate(tt_attr, PTHREAD_CREATE_JOINABLE);//PTHREAD_CREATE_DETACHED printf("%d\t%d\t%d\n",*x,glabol,k); k=pthread_create(&tt,tt_attr,cal,x); printf("c'est parti\n"); k+=2; cal(&k); glabol*=2; printf("%d\t%d\t%d\n",*x,glabol,k); /* uu_attr =new pthread_attr_t; pthread_attr_init(uu_attr); pthread_attr_setdetachstate(uu_attr, PTHREAD_CREATE_JOINABLE);//PTHREAD_CREATE_DETACHED*/ k=pthread_create(&tt,tt_attr,cal,x); pthread_join(tt,NULL); printf("%d\t%d\t%d\n",*x,glabol,k); scanf("%d",&k); return 0; } // programme modifiant bien glabol et x , x est bien l'argument passer à la fonction lors de lapel du thread // pthread_t : unsigned long int !! // g++ -lpthread
NicoBoklo
Messages postés
87
Date d'inscription
samedi 2 décembre 2006
Statut
Membre
Dernière intervention
8 septembre 2010
2
8 avril 2008 à 15:25
8 avril 2008 à 15:25
Merci,
Je vais regarder ce programme et tenter de comprendre comment tout marche!
Je vais regarder ce programme et tenter de comprendre comment tout marche!