Voila, un mini-chat multithread ,multi client en console, Je poste cet première source, pas pour montrer quelques chose d'innovant mais plutôt pour que les plus expérimenter m'aide a améliorer ma façon de programmer car vous allez surement la trouver un peu barbare notamment l'utilisation de variable globale car je n'arrivai pas a passer des arguments a un thread.
Néanmoins je suis sur que cette source pourra en apprendre beaucoup au débutant sur l'utilisation des sockets car je l'est énormément commenter(un peu trop même,lol).
n'oubliez pas d'inclure la librairie winsock2 ainsi que pthread(la dll est dans le projet).
Source / Exemple :
///////////////////////////////////////////////SERVEUR///////////////////////////////////////////////
#include <stdio.h>
#include <windows.h>
#include <pthread.h>//utilisation des threads
#include <winsock2.h>//pour les sockets
#define PORT 2000 //le port sur lequel le serveur ecoute
#define MAX_CLIENT 3 // cette constante sert a definir le nombre de maximum de client qui sera autoriser par le serveur
struct Client//structure ou sera enregistre les information pour chaque client
{
SOCKET SockClient;// son socket
bool Connecte;//si ce client est deja utiliser ou pas (1 si deja utiliser,sinon 0)
pthread_t ThreadReception; //son thread de reception( la fonction recv est une fonction "bloquante" donc utilisation de thread
char Pseudo[50];//le pseudo du client
};
Client client[MAX_CLIENT];//tableau de type Client,ou seront stoquer tout les clients
int IDNouveauThread=0;//variable temporaire qui me sert a envoyer une variable d'une fonction a une autre( car j'arrive pas a envoyer une variable a une fonction lancer en thread)
int ServeurPlein=0;//1:le serveur est plein,0 le serveur a encore des emplacement de libre
void *Reception(void *data);//fonction qui ecoute un client et renvoie les donnees recu au autre client
int EnvoieDonnee(SOCKET SockClient,char *Donnee);/*envoie donnee au client
renvoie 1 si tout c'est bien passer sinon revoie 0*/
int Ecoute();/*fonction qui met en ecoutesur le port selectionne plus haut(attente de client)
revoie 1 si l'ecoute a ete lancer avec succes
sinon revoie 0*/
SOCKET SockServeur;
int Retour=0;
SOCKADDR_IN Sin = {0};
int main(void)
{
int I=0;
if (Ecoute())//on lance l'ecoute sur le port(defini plus haut)
{
printf("Le Serveur ecoute sur le port %d\nEn attente de la connections des clients\n",PORT);//si 1, c ok
}
else
{
printf("Erreur lors de la mise en ecoute sur le port no %d\n",PORT);//0 erreur, on est obliger de sortir
system("pause");
return 0;
}
I=0;//variable qui va servir a parcourir le tableau de Client
do
{
if (I>=MAX_CLIENT)//veut dire que l'on a atteint la limite maxi des clients
{
printf("Serveur Plein\n");
ServeurPlein=1;//on indique que le Serveur est saturer
shutdown(SockServeur, 1);//on eteint le socket de reception
closesocket(SockServeur);//idem
do
{
Sleep(1000);//sert a evite de charger le processeur
}
while (ServeurPlein);//temps que la variable ServeurPlein est a 1 cela veut dire que aucun emplacement a ete liberer
//un emplacement a ete liberer
if (Ecoute())//on relance l'ecoute
{
printf("Serveur en attente de client\n");
}
else
{
printf("Erreur lors de la mise en ecoute sur le port no %d\n",PORT);
system("pause");
return 0;
}
I=0;//on remet i a 0 pour la prochaine recherche
}
else
{
if (client[I].Connecte==false)//veut dire que cette emplacement de client n'est pas utiliser, donc OK
{
printf("Emplacement libre trouver:%d\n",I);
Sleep(10);
SOCKADDR_IN CSin = {0};
int sizeofcsin = sizeof(CSin);
client[I].SockClient = accept(SockServeur, (SOCKADDR *)&CSin, &sizeofcsin);//on accepte la connection
if ( client[I].SockClient != INVALID_SOCKET )//si la connection a reussi
{
client[I].Connecte=true;//on passe la variable a 1 pour indique que se client est dorenavant utilise
Retour = recv(client[I].SockClient, client[I].Pseudo, sizeof(client[I].Pseudo)-1, 0);//on recoit le pseudo
printf("Client no %d connecte sous le pseudo: %s\n\n",I,client[I].Pseudo);
IDNouveauThread=I;//je passe ma variable i dans une variable temporaire pour savoir sur quelle client je doit ecouter pour la fonction suivante
pthread_create(&client[I].ThreadReception, NULL, Reception, NULL);//on lance le thread ou va etre recu les donnes de se client
I=0;//on repasse i a 0 pour une prochaine recherche d'emplacement libre
}
else
{
printf("Erreur\n");
}
}
I++;//on poursuit la recherche de nouveau client
}
}
while (1);
WSACleanup();
system("pause");
return 0;
}
void *Reception(void *Donnee)
{
int RetourReception;
int I=0;
int IDThreadActuel=IDNouveauThread;
char DonneeRecu[1024];//variable ou sera stocker les donnees recu
char DonneeAEnvoyer[1024];
int Connecte=true;//la conection au serveur est ok
do
{
I=0;// variable qui va servir a parcourir les clients auquel on va envoyer les donnees recu d'un client
RetourReception = recv(client[IDThreadActuel].SockClient, DonneeRecu, sizeof(DonneeRecu)-1, 0);//on recoit les donnees(fonction "bloquante"
if (RetourReception != SOCKET_ERROR)//connection avec le client OK
{
DonneeRecu[RetourReception] = '\0';
do
{
if (client[I].Connecte==true)//cela veut dire que se client est connecte donc on peut lui envoyer les donnees que l'on vient de recevoir
{
if (I!=IDThreadActuel)//pour ne pas envoyer les donnees au client qui vient de les envoyer(ben oui on sait se que l'on vient de taper lol)
{
DonneeAEnvoyer[0]='\0';
strcat(DonneeAEnvoyer,client[IDThreadActuel].Pseudo);
strcat(DonneeAEnvoyer," dit: ");
strcat(DonneeAEnvoyer,DonneeRecu);
if (!EnvoieDonnee(client[I].SockClient,DonneeAEnvoyer))//si l'envoie de donnee a echouer
{
printf("%s deconnecte\n",client[I].Pseudo);
closesocket(client[I].SockClient);//on ferme son socket client
client[I].Connecte=false;//on indique que cet emplacement est desormais libre
ServeurPlein=0;//le serveur n'est plus plein si il l'etait(je sais j'aurais pu mettre un if pour verifier si il l'etait...)
}
}
}
I++;//on continue a parcourir les autres clients
}
while (I<MAX_CLIENT);//tant que l'on a pas atteind la limite de client
I=0;//pour une prochaine recherche lors de la prochaine reception de donnee
}
else//connection avec le client NOK
{
printf("%s deconnecte\n",client[IDThreadActuel].Pseudo);
shutdown(client[IDThreadActuel].SockClient, 2);//on ferme le socket de se thread
closesocket(client[IDThreadActuel].SockClient);//idem
client[IDThreadActuel].Connecte=false;//on indique que cet emplacement est desormais libre
ServeurPlein=0;//voir plus haut
Connecte=false;//on sort de la boucle pour terminer le thread puisque l'on a perdu la connection avec ce client
}
}
while (Connecte);
return &Donnee;
}
int EnvoieDonnee(SOCKET SockClient,char *Donnee)
{
int RetourEnvoie;
RetourEnvoie=send(SockClient, Donnee, strlen(Donnee), 0);//envoie les donnee (variable data)
if (RetourEnvoie!=SOCKET_ERROR)
{
return 1;
}
return 0;
}
int Ecoute()
{
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);//init winsock
SOCKADDR_IN Sin = {0};//structure qui va contenir les informations de notre socket serveur
SockServeur = socket(AF_INET, SOCK_STREAM, 0);//creation du socket
if ( SockServeur != INVALID_SOCKET )//si creation ok
{
Sin.sin_addr.s_addr = htonl(INADDR_ANY);//on rempli la structure
Sin.sin_family = AF_INET;//idem
Sin.sin_port = htons(PORT);//idem
Retour = bind(SockServeur, (SOCKADDR *)&Sin, sizeof(Sin));//on associe le socket a notre adresse local(enfin je crois,lol)
if ( Retour != SOCKET_ERROR )//si ok
{
Retour = listen(SockServeur, 2);//on commence ll'ecoute (l'attente de client)
if ( Retour != SOCKET_ERROR )//si tout c'est bien passer
{
return 1;
}
}
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////CLIENT////////////////////////////////////////////////
#include <stdio.h>
#include <windows.h>
#include <winsock2.h>
#include <pthread.h>//utilisation des thread car fonction recv bloquante
#define TPSATTENTE 5
SOCKET Sock;
pthread_t ThreadReception;
void *Reception(void *Donnee);//fonction ou se fait la reception de donnee envoyer par le serveur
int main(void)
{
char Ip[16];
unsigned int Port=0;
char Pseudo[50];
int Erreur;
int TempsDAttente=0;
bool Connecte=false;
printf("\t\t\t\tClient multiThread\n\n\n");
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);//init winsock
printf("Choisir un Pseudo:\n");// un pseudo
Pseudo[0]='\0';
fgets(Pseudo,sizeof Pseudo,stdin);
Pseudo[strlen(Pseudo)-1]='\0';//pour retirer le retour chariot qui est enregistre dans le fgets
printf("Adresse du serveur:\n"); //on recupere les differente infos, adresse
Ip[0]='\0';
fgets(Ip,sizeof Ip,stdin);
Ip[strlen(Ip)-1]='\0';//pour retirer le retour chariot qui est enregistre dans le fgets
printf("Port de connection:\n"); //port de connection
scanf("%d",&Port);
Sock = socket(AF_INET, SOCK_STREAM, 0);//on creer le socket
if ( Sock != INVALID_SOCKET )//si creation ok
{
printf("\nSocket client no %d ouvert\n",Sock);
SOCKADDR_IN Sin;
Sin.sin_addr.s_addr = inet_addr(Ip); //on rempli la structure sin qui va servir au socket
Sin.sin_family = AF_INET;
Sin.sin_port = htons(Port);
printf("Connection a %s sur le port %d en cours...\n",Ip,Port);
do
{
Erreur = connect(Sock, (SOCKADDR *)&Sin, sizeof Sin);//on essaye de se connecte au serveur
if (Erreur != SOCKET_ERROR)
{
Connecte=true;
}
else
{
if (TempsDAttente<=TPSATTENTE)
{
Sleep(1000);// on attend 1 seconde avant de reesayer (pour eviter de charge le processeur
TempsDAttente++;
}
else
{
printf("Temps de connection trop long");
goto deconnection;
}
}
}
while (!Connecte);//tant que l'on arrive pas a se connecter
printf("Connection au serveur effectue avec succes\n\n");
char DonneeAEnvoyer[512];
Erreur = send(Sock, Pseudo, strlen(Pseudo), 0);//on envoie le pseudo au serveur
if (Erreur == SOCKET_ERROR)//si il y a erreur cela veut dire que l'on a perdu la connection avec le serveur donc on sort
{
goto deconnection;
}
pthread_create(&ThreadReception, NULL, Reception, NULL);//on lance le thread qui va recevoir les donnees du serveur
do
{
DonneeAEnvoyer[0]='\0';//pour etre sur de ne pas envoyer autre chose que se qui a ete saisie
fgets(DonneeAEnvoyer, sizeof DonneeAEnvoyer, stdin);//on recupere les saisies du clavier
Erreur = send(Sock, DonneeAEnvoyer, strlen(DonneeAEnvoyer), 0);//on les envoie au serveur
if (Erreur == SOCKET_ERROR)
{
Connecte=false;//si erreur, on sort de la boucle
}
}
while (Connecte);
deconnection:
printf("Connection avec le serveur interrompu\n");
closesocket(Sock);//on ferme le socket
}
else
{
printf("Socket invalide\n");
return EXIT_FAILURE;
}
WSACleanup();//on nettoie le wsa.
system("pause");
return EXIT_SUCCESS;
}
void *Reception(void *Donnee)
{
int Erreur;
bool Connecte=true;
char DonneeRecu[50];
do
{
Erreur = recv(Sock, DonneeRecu, sizeof(DonneeRecu)-1, 0);//on recoit les donnees, fonction bloquante d'ou le thread
if (Erreur == SOCKET_ERROR)
{
Connecte=false;//voir plus haut
}
else
{
DonneeRecu[Erreur] = '\0';
printf(">>>> %s",DonneeRecu);
}
}
while (Connecte);
printf("perte de la connection avec le serveur\n");
closesocket(Sock);//on ferme le socket
return &Donnee;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.