begin process at 2010 02 10 08:38:14
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Réseaux & Internet

 > SERVEUR DE CHAT MULTITHREADE EN C SOUS LINUX

SERVEUR DE CHAT MULTITHREADE EN C SOUS LINUX


 Information sur la source

Note :
10 / 10 - par 3 personnes
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Réseaux & Internet Niveau :Initié Date de création :28/08/2004 Vu / téléchargé :10 520 / 1 178

Auteur : MetalDwarf

Ecrire un message privé
Commentaire sur cette source (26)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
Voila un petit serveur de chat en C sous Linux. Il permet de gerer de nombreux clients dans un seul processus, et peut servir d exemple pour creer un serveur avec les thread. La protection des donnees est assuree avec des mutex sur les structures globales. Ce serveur inclut les fonctionnalites standards, c est a dire la gestion des pseudo, des droits admin, certaines commandes,etc... Il peut etre facilement complete. De plus il contient des fonctions utiles pour la programmation reseau sous Linux. Il n y a *en principe* pas de bug.
Ce code compile sans probleme sous Linux 2.6 (2.6.7 pour etre precis) avec gcc (3.4.0). Il devrait fonctionner sans probleme sur tout Unix compatible POSIX pour les threads, et sans doute sur Linux 2.4 (ce qui n est pas totalement sur a cause d une gestion partielle des threads dans Linux 2.4, mais en principe aucune des nouvelles fonctionnalites de Linux 2.6 n est utilisee).

Source

  • /* serveur de chat sous Linux avec les thread */
  • /* gcc server.c -o server -lpthread -D_REENTRANT */
  • #include <errno.h>
  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <string.h>
  • #include <sys/socket.h>
  • #include <sys/types.h>
  • #include <sys/time.h>
  • #include <sys/resource.h>
  • #include <sys/wait.h>
  • #include <unistd.h>
  • #include <netinet/in.h>
  • #include <netdb.h>
  • #include <arpa/inet.h>
  • #include <fcntl.h>
  • #include <pthread.h>
  • #define BANNER "Serveur de chat v0.4 par .:MiniMoi:.\n(C) .:MiniMoi:. 2004\n"
  • #define CLIENT_BANNER "Connection etablie...\r\nBienvenue sur le serveur de chat de MiniMoi\r\nEntrez votre pseudo: "
  • #define ADMIN_PWD "MiniMoi"
  • #define HELP_MSG "Commandes disponibles :\r\n- /pseudo=[nouveau pseudo] --> changer de pseudo\r\n- /quit=[message] --> quitter avec (ou sans) message\r\n- /list --> obtenir la liste des clients connectes\r\n- /admin=[password] --> obtenir les droits administrateur\r\n- /kick=[pseudo] --> kicker un client(reserve aux admins)\r\n- /? --> afficher cette aide\r\n"
  • #define MAX_CLIENTS 500
  • #define LS_CLIENT_NB 5
  • #define INVALID_SOCKET -1
  • #define PORT 1987
  • volatile int nb_clients = 0;
  • int first_free = 0;
  • pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • typedef struct _s_client
  • {
  • pthread_t id;
  • int sock;
  • char *pseudo;
  • char admin;
  • } s_client;
  • s_client *clients[MAX_CLIENTS];
  • /* creation d'un serveur */
  • int create_server(int port)
  • {
  • int sock,optval = 1;
  • struct sockaddr_in sockname;
  • if((sock = socket(PF_INET,SOCK_STREAM,0))<0)
  • {
  • printf("Erreur d'ouverture de la socket");
  • exit(-1);
  • }
  • setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(int));
  • memset((char *) &sockname,0,sizeof(struct sockaddr_in));
  • sockname.sin_family = AF_INET;
  • sockname.sin_port = htons(port);
  • sockname.sin_addr.s_addr = htonl(INADDR_ANY);
  • if(bind(sock,(struct sockaddr *) &sockname, sizeof(struct sockaddr_in)) < 0)
  • {
  • printf("Erreur de bind!");
  • exit(-1);
  • }
  • if(listen(sock,LS_CLIENT_NB) <0)
  • {
  • printf("listen error!");
  • exit(-1);
  • }
  • return sock;
  • }
  • /* accepte une connexion avec ou sans timeout */
  • int server_accept(int main_sock,int timeout)
  • {
  • int sock;
  • if(timeout > 0)
  • alarm(timeout);
  • if((sock = accept(main_sock,NULL,0)) < 0)
  • {
  • if(errno == EINTR)
  • {
  • shutdown(main_sock,SHUT_RDWR);
  • close(main_sock);
  • if(timeout > 0)
  • alarm(0);
  • return -1;
  • }
  • else
  • {
  • printf("\nAccept error.\n");
  • exit(-1);
  • }
  • }
  • if(timeout > 0)
  • alarm(0);
  • fcntl(sock,F_SETFD,1);
  • return sock;
  • }
  • /* envoyer une chaine de caractere a un client */
  • int send_msg(int sock,char *msg)
  • {
  • return write(sock,msg,strlen(msg));
  • }
  • /* envoyer un message a tout le monde sauf a la socket not_to */
  • int send_all(char *msg, int not_to)
  • {
  • int i;
  • pthread_mutex_lock(&mutex); // debut de la section critique
  • for(i=0;i<first_free;i++)
  • {
  • if(clients[i]->sock != not_to)
  • send_msg(clients[i]->sock,msg);
  • }
  • pthread_mutex_unlock(&mutex); // fin de la section critique
  • return 0;
  • }
  • /* gestion de fin de connection d'un client */
  • void client_quit(s_client *me, char *msg)
  • {
  • int i,j;
  • char buf[8192+1];
  • if(msg) snprintf(buf,8192,"%s nous quitte...(%s)\r\n",me->pseudo,msg);
  • else snprintf(buf,8192,"%s nous quitte...\r\n",me->pseudo);
  • buf[8192] = '\0';
  • send_all(buf,me->sock);
  • pthread_mutex_lock(&mutex); // debut de la section critique
  • for(i=0;(clients[i]->sock != me->sock);i++); // recherche de l'index de la structure dans le tableau
  • close(me->sock);
  • free(me->pseudo);
  • free(me);
  • for(j=i+1;j<first_free;j++) // on reorganise le tableau en decalant les elements situes APRES celui qui est supprime
  • {
  • clients[j-1] = clients[j];
  • }
  • nb_clients--;
  • first_free--;
  • pthread_mutex_unlock(&mutex); // fin de la section critique
  • printf("Un client en moins...%d clients\n",nb_clients);
  • }
  • /* interaction avec le client (thread) */
  • void *interact(void *param)
  • {
  • int sck = *((int *) param);
  • char msg[4096+1];
  • char msg_to_send[8192+1];
  • s_client *me = NULL;
  • char *buf = NULL;
  • int len;
  • int i;
  • me = (s_client *) malloc(sizeof(s_client));
  • if(!me)
  • {
  • printf("\nErreur d'allocation memoire!\n");
  • close(sck);
  • nb_clients--;
  • pthread_exit(NULL);
  • }
  • bzero(me,sizeof(s_client));
  • send_msg(sck,CLIENT_BANNER);
  • len = read(sck,msg,4096);
  • if(len <= 0)
  • {
  • printf("\nErreur\n");
  • close(sck);
  • free(me);
  • me = NULL;
  • nb_clients--;
  • pthread_exit(NULL);
  • }
  • msg[255] = '\0'; // on limite le pseudo a 255 caracteres
  • for(i=0;(msg[i]!='\0') && (msg[i]!='\r') && (msg[i]!='\n') && (msg[i]!='\t');i++);
  • msg[i] = '\0'; // on isole le pseudo
  • pthread_mutex_lock(&mutex); // debut de la section critique
  • for(i=0;i<first_free;i++)
  • {
  • if(!strcmp(msg,clients[i]->pseudo))
  • {
  • send_msg(sck,"\r\nPseudo deja utilise! Deconnection...\r\n");
  • close(sck);
  • free(me);
  • nb_clients--;
  • pthread_mutex_unlock(&mutex); // fin de la section critique
  • pthread_exit(NULL);
  • }
  • }
  • pthread_mutex_unlock(&mutex); // fin de la section critique
  • me->id = pthread_self();
  • me->sock = sck;
  • me->pseudo = strdup(msg);
  • me->admin = 0;
  • pthread_mutex_lock(&mutex); // debut de la section critique
  • clients[first_free] = me;
  • first_free++;
  • pthread_mutex_unlock(&mutex); // fin de la section critique
  • snprintf(msg_to_send,8192,"Nouveau client : %s\r\n",me->pseudo);
  • msg_to_send[8192]='\0';
  • send_all(msg_to_send,INVALID_SOCKET);
  • while(1)
  • {
  • len = read(sck,msg,4096);
  • if(len <= 0)
  • {
  • client_quit(me,"Erreur reseau");
  • pthread_exit(NULL);
  • }
  • msg[len] = '\0';
  • if(msg[0] == '/') // le message est une commande
  • {
  • int valid_command = 0;
  • if(!strncmp(msg,"/pseudo=",8)) // changement de pseudo
  • {
  • char *old_pseudo = NULL;
  • int valid_pseudo = 1;
  • msg[255+8] = '\0'; // on limite le pseudo a 255 caracteres
  • for(i=8;(msg[i]!='\0') && (msg[i]!='\r') && (msg[i]!='\n') && (msg[i]!='\t');i++);
  • msg[i] = '\0'; // on isole le pseudo
  • /* on verifie que le nouveau pseudo n'existe pas deja */
  • pthread_mutex_lock(&mutex); // debut de la section critique
  • for(i=0;i<first_free;i++)
  • {
  • if(!strcmp(&msg[8],clients[i]->pseudo))
  • valid_pseudo = 0;
  • }
  • pthread_mutex_unlock(&mutex); // fin de la section critique
  • if(valid_pseudo)
  • {
  • old_pseudo = me->pseudo;
  • me->pseudo = strdup(&msg[8]);
  • snprintf(msg_to_send,8192,"%s s'appelle maintenant %s\r\n",old_pseudo,me->pseudo);
  • free(old_pseudo);
  • send_all(msg_to_send,INVALID_SOCKET);
  • }
  • else send_msg(sck,"Pseudo deja utilise!\r\n");
  • valid_command = 1;
  • }
  • if(!strncmp(msg,"/quit",5)) // sortie "propre" du serveur (avec message)
  • {
  • int i;
  • if(msg[5]=='=')
  • {
  • for(i=6;(msg[i]!='\0') && (msg[i]!='\r') && (msg[i]!='\n') && (msg[i]!='\t');i++);
  • msg[i]='\0';
  • client_quit(me,&msg[6]);
  • }
  • else client_quit(me,NULL);
  • pthread_exit(NULL);
  • valid_command = 1; // inutile car pthread_exit() quitte le thread...
  • }
  • if(!strncmp(msg,"/list",5)) // obtenir la liste des pseudos sur le serveur
  • {
  • pthread_mutex_lock(&mutex); // debut de la section critique
  • for(i=0;i<first_free;i++)
  • {
  • send_msg(me->sock,clients[i]->pseudo);
  • send_msg(me->sock,"\r\n");
  • }
  • pthread_mutex_unlock(&mutex); // fin de la section critique
  • valid_command = 1;
  • }
  • if(!strncmp(msg,"/admin=",7)) // droits admin (avec mot de passe)
  • {
  • if(!strncmp(&msg[7],ADMIN_PWD,strlen(ADMIN_PWD)))
  • {
  • send_msg(me->sock,"Droits administrateur actives.\r\n");
  • me->admin = 1;
  • }
  • else send_msg(me->sock,"Mot de passe incorrect!\r\n");
  • valid_command = 1;
  • }
  • if(!strncmp(msg,"/kick=",6))
  • {
  • if(me->admin)
  • {
  • int i;
  • char *pseudo = &msg[6];
  • int trouve = 0;
  • pseudo[255+8] = '\0'; // on limite le pseudo a 255 caracteres
  • for(i=0;(pseudo[i]!='\0') && (pseudo[i]!='\r') && (pseudo[i]!='\n') && (pseudo[i]!='\t');i++);
  • pseudo[i] = '\0'; // on isole le pseudo
  • /* on cherche si le pseudo existe */
  • pthread_mutex_lock(&mutex); // debut de la section critique
  • for(i=0;i<first_free;i++)
  • {
  • if(!strcmp(pseudo,clients[i]->pseudo))
  • {
  • trouve = 1;
  • if(!clients[i]->admin)
  • {
  • pthread_t th_id = clients[i]->id;
  • s_client *client = clients[i];
  • pthread_mutex_unlock(&mutex);
  • send_msg(client->sock,"Vous etes kicke par un admin\r\n");
  • client_quit(client,"Kicke par un admin");
  • pthread_cancel(th_id); // termine le thread correspondant
  • send_msg(me->sock,"Le client a ete kicke!\r\n");
  • break;
  • }
  • else send_msg(me->sock,"Impossible de kicker un admin!\r\n");
  • }
  • }
  • pthread_mutex_unlock(&mutex); // fin de la section critique
  • if(!trouve)
  • send_msg(me->sock,"Impossible de trouver le pseudo!\r\n");
  • }
  • else send_msg(me->sock,"Cette commande necessite les droits administrateur!\r\n");
  • valid_command = 1;
  • }
  • if(!strncmp(msg,"/?",2))
  • {
  • send_msg(me->sock,HELP_MSG);
  • valid_command = 1;
  • }
  • if(!valid_command) // commande invalide
  • send_msg(sck,"Commande non valide!\r\n");
  • }
  • else // message normal
  • { snprintf(msg_to_send,8192,"%s : %s",me->pseudo,msg);
  • msg_to_send[8192] = '\0';
  • send_all(msg_to_send,me->sock);
  • }
  • }
  • return NULL;
  • }
  • /* fonction principale */
  • int main(int argc, char **argv)
  • {
  • int server,sck;
  • pthread_t th_id;
  • printf(BANNER);
  • server = create_server(PORT);
  • while(1)
  • {
  • sck = server_accept(server,0);
  • if(sck == INVALID_SOCKET)
  • {
  • printf("\nErreur de accept()!\n");
  • exit(-1);
  • }
  • if(nb_clients < MAX_CLIENTS)
  • {
  • pthread_create(&th_id,NULL,interact,(void *)&sck);
  • nb_clients++;
  • printf("Nouveau client! %d clients\n",nb_clients);
  • }
  • else close(sck);
  • }
  • return 0;
  • }
/* serveur de chat sous Linux avec les thread */
/* gcc server.c -o server -lpthread -D_REENTRANT */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <pthread.h>

#define BANNER "Serveur de chat v0.4 par .:MiniMoi:.\n(C) .:MiniMoi:. 2004\n"
#define CLIENT_BANNER "Connection etablie...\r\nBienvenue sur le serveur de chat de MiniMoi\r\nEntrez votre pseudo: "
#define ADMIN_PWD "MiniMoi"
#define HELP_MSG "Commandes disponibles :\r\n- /pseudo=[nouveau pseudo] --> changer de pseudo\r\n- /quit=[message] --> quitter avec (ou sans) message\r\n- /list --> obtenir la liste des clients connectes\r\n- /admin=[password] --> obtenir les droits administrateur\r\n- /kick=[pseudo] --> kicker un client(reserve aux admins)\r\n- /? --> afficher cette aide\r\n"

#define MAX_CLIENTS 500
#define LS_CLIENT_NB 5
#define INVALID_SOCKET -1
#define PORT 1987

volatile int nb_clients = 0;
int first_free = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

typedef struct _s_client
{
	pthread_t id;
	int sock;
	char *pseudo;
	char admin;
} s_client;

s_client *clients[MAX_CLIENTS];

/* creation d'un serveur */
int create_server(int port)
{
  int sock,optval = 1;
  struct sockaddr_in sockname;

  if((sock = socket(PF_INET,SOCK_STREAM,0))<0)
    {
      printf("Erreur d'ouverture de la socket");
      exit(-1);
    }
  
  setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(int));
  memset((char *) &sockname,0,sizeof(struct sockaddr_in));
  sockname.sin_family = AF_INET;
  sockname.sin_port = htons(port);
  sockname.sin_addr.s_addr = htonl(INADDR_ANY);

  if(bind(sock,(struct sockaddr *) &sockname, sizeof(struct sockaddr_in)) < 0)
    {
      printf("Erreur de bind!");
      exit(-1);
    }

  if(listen(sock,LS_CLIENT_NB) <0)
    {
      printf("listen error!");
      exit(-1);
    }
  
  return sock;
}

/* accepte une connexion avec ou sans timeout */
int server_accept(int main_sock,int timeout)
{
  int sock;

  if(timeout > 0)
    alarm(timeout);

  if((sock = accept(main_sock,NULL,0)) < 0)
    {
      if(errno == EINTR)
	{
	  shutdown(main_sock,SHUT_RDWR);
	  close(main_sock);
	  if(timeout > 0)
	    alarm(0);
	  return -1;
	}
      else
	{
	  printf("\nAccept error.\n");
	  exit(-1);
	}
    }

  if(timeout > 0)
    alarm(0);
  fcntl(sock,F_SETFD,1);
  
  return sock;
}

/* envoyer une chaine de caractere a un client */
int send_msg(int sock,char *msg)
{
	return write(sock,msg,strlen(msg));
}

/* envoyer un message a tout le monde sauf a la socket not_to */
int send_all(char *msg, int not_to)
{
	int i;
	
	pthread_mutex_lock(&mutex);	// debut de la section critique
	for(i=0;i<first_free;i++)
	{
		if(clients[i]->sock != not_to)
			send_msg(clients[i]->sock,msg);
	}
	pthread_mutex_unlock(&mutex);	// fin de la section critique
	
	return 0;
}

/* gestion de fin de connection d'un client */
void client_quit(s_client *me, char *msg)
{
	int i,j;
	char buf[8192+1];
	
	if(msg)	snprintf(buf,8192,"%s nous quitte...(%s)\r\n",me->pseudo,msg);
	else	snprintf(buf,8192,"%s nous quitte...\r\n",me->pseudo);
	buf[8192] = '\0';
	send_all(buf,me->sock);
	pthread_mutex_lock(&mutex);	// debut de la section critique
	for(i=0;(clients[i]->sock != me->sock);i++);	// recherche de l'index de la structure dans le tableau
	
	close(me->sock);
	free(me->pseudo);
	free(me);
	
	for(j=i+1;j<first_free;j++)	// on reorganise le tableau en decalant les elements situes APRES celui qui est supprime
	{
		clients[j-1] = clients[j];
	}
	nb_clients--;
	first_free--;
	pthread_mutex_unlock(&mutex);	// fin de la section critique
	printf("Un client en moins...%d clients\n",nb_clients);
}

/* interaction avec le client (thread) */
void *interact(void *param)
{
	int sck = *((int *) param);
	char msg[4096+1];
	char msg_to_send[8192+1];
	s_client *me = NULL;
	char *buf = NULL;
	int len;
	int i;
	
	me = (s_client *) malloc(sizeof(s_client));
	if(!me)
	{
		printf("\nErreur d'allocation memoire!\n");
		close(sck);
		nb_clients--;
		pthread_exit(NULL);
	}
	bzero(me,sizeof(s_client));
	
	send_msg(sck,CLIENT_BANNER);
	len = read(sck,msg,4096);
	if(len <= 0)
	{
		printf("\nErreur\n");
		close(sck);
		free(me);
		me = NULL;
		nb_clients--;
		pthread_exit(NULL);
	}
	msg[255] = '\0';	// on limite le pseudo a 255 caracteres
	for(i=0;(msg[i]!='\0') && (msg[i]!='\r') && (msg[i]!='\n') && (msg[i]!='\t');i++);
	msg[i] = '\0';	// on isole le pseudo
	
	pthread_mutex_lock(&mutex);	// debut de la section critique
	for(i=0;i<first_free;i++)
	{
		if(!strcmp(msg,clients[i]->pseudo))
		{
			send_msg(sck,"\r\nPseudo deja utilise! Deconnection...\r\n");
			close(sck);
			free(me);
			nb_clients--;
			pthread_mutex_unlock(&mutex);	// fin de la section critique
			pthread_exit(NULL);
		}
	}
	pthread_mutex_unlock(&mutex);	// fin de la section critique
	
	me->id = pthread_self();
	me->sock = sck;
	me->pseudo = strdup(msg);
	me->admin = 0;
	
	pthread_mutex_lock(&mutex);	// debut de la section critique
	clients[first_free] = me;
	first_free++;
	pthread_mutex_unlock(&mutex);	// fin de la section critique
	
	snprintf(msg_to_send,8192,"Nouveau client : %s\r\n",me->pseudo);
	msg_to_send[8192]='\0';
	send_all(msg_to_send,INVALID_SOCKET);
	while(1)
	{
		len = read(sck,msg,4096);
		if(len <= 0)
		{
			client_quit(me,"Erreur reseau");
			pthread_exit(NULL);
		}
		msg[len] = '\0';
		if(msg[0] == '/')	// le message est une commande
		{
			int valid_command = 0;
			
			if(!strncmp(msg,"/pseudo=",8))	// changement de pseudo
			{
				char *old_pseudo = NULL;
				int valid_pseudo = 1;
				
				msg[255+8] = '\0';	// on limite le pseudo a 255 caracteres
				for(i=8;(msg[i]!='\0') && (msg[i]!='\r') && (msg[i]!='\n') && (msg[i]!='\t');i++);
				msg[i] = '\0';	// on isole le pseudo
				
				/* on verifie que le nouveau pseudo n'existe pas deja */
				pthread_mutex_lock(&mutex);	// debut de la section critique
				for(i=0;i<first_free;i++)
				{
					if(!strcmp(&msg[8],clients[i]->pseudo))
						valid_pseudo = 0;
				}
				pthread_mutex_unlock(&mutex);	// fin de la section critique
								
				if(valid_pseudo)
				{
					old_pseudo = me->pseudo;
					me->pseudo = strdup(&msg[8]);
					snprintf(msg_to_send,8192,"%s s'appelle maintenant %s\r\n",old_pseudo,me->pseudo);
					free(old_pseudo);
					send_all(msg_to_send,INVALID_SOCKET);
				}
				else send_msg(sck,"Pseudo deja utilise!\r\n");
				valid_command = 1;
			}
			if(!strncmp(msg,"/quit",5))	// sortie "propre" du serveur (avec message)
			{
				int i;
				
				if(msg[5]=='=')
				{
					for(i=6;(msg[i]!='\0') && (msg[i]!='\r') && (msg[i]!='\n') && (msg[i]!='\t');i++);
					msg[i]='\0';
					client_quit(me,&msg[6]);
				}
				else client_quit(me,NULL);
				pthread_exit(NULL);
				valid_command = 1;	// inutile car pthread_exit() quitte le thread...
			}
			if(!strncmp(msg,"/list",5))	// obtenir la liste des pseudos sur le serveur
			{
				pthread_mutex_lock(&mutex);	// debut de la section critique
				for(i=0;i<first_free;i++)
				{
					send_msg(me->sock,clients[i]->pseudo);
					send_msg(me->sock,"\r\n");
				}
				pthread_mutex_unlock(&mutex);	// fin de la section critique
				valid_command = 1;
			}
			if(!strncmp(msg,"/admin=",7))	// droits admin (avec mot de passe)
			{
				if(!strncmp(&msg[7],ADMIN_PWD,strlen(ADMIN_PWD)))
				{
					send_msg(me->sock,"Droits administrateur actives.\r\n");
					me->admin = 1;
				}
				else send_msg(me->sock,"Mot de passe incorrect!\r\n");
				valid_command = 1;
			}
			if(!strncmp(msg,"/kick=",6))
			{
				if(me->admin)
				{
					int i;
					char *pseudo = &msg[6];
					int trouve = 0;
					
					pseudo[255+8] = '\0';	// on limite le pseudo a 255 caracteres
					for(i=0;(pseudo[i]!='\0') && (pseudo[i]!='\r') && (pseudo[i]!='\n') && (pseudo[i]!='\t');i++);
					pseudo[i] = '\0';	// on isole le pseudo

					/* on cherche si le pseudo existe */
					pthread_mutex_lock(&mutex);	// debut de la section critique
					for(i=0;i<first_free;i++)
					{
						if(!strcmp(pseudo,clients[i]->pseudo))
						{
							trouve = 1;
							if(!clients[i]->admin)
							{
								pthread_t th_id = clients[i]->id;
								s_client *client = clients[i];
								pthread_mutex_unlock(&mutex);
								send_msg(client->sock,"Vous etes kicke par un admin\r\n");
								client_quit(client,"Kicke par un admin");	
								pthread_cancel(th_id);	// termine le thread correspondant
								send_msg(me->sock,"Le client a ete kicke!\r\n");
								break;
							}
							else send_msg(me->sock,"Impossible de kicker un admin!\r\n");
						}
					}
					pthread_mutex_unlock(&mutex);	// fin de la section critique
					
					if(!trouve)
						send_msg(me->sock,"Impossible de trouver le pseudo!\r\n");
				}
				else send_msg(me->sock,"Cette commande necessite les droits administrateur!\r\n");
				valid_command = 1;
			}
			if(!strncmp(msg,"/?",2))
			{
				send_msg(me->sock,HELP_MSG);
				valid_command = 1;
			}
				
			if(!valid_command)	// commande invalide
				send_msg(sck,"Commande non valide!\r\n");
		}
		else			// message normal
		{	snprintf(msg_to_send,8192,"%s : %s",me->pseudo,msg);
			msg_to_send[8192] = '\0';
			send_all(msg_to_send,me->sock);
		}
	}
	
	return NULL;
}

/* fonction principale */
int main(int argc, char **argv)
{
	int server,sck;
	pthread_t th_id;
	
	printf(BANNER);
	
	server = create_server(PORT);
	while(1)
	{
		sck = server_accept(server,0);
		if(sck == INVALID_SOCKET)
		{
			printf("\nErreur de accept()!\n");
			exit(-1);
		}
		if(nb_clients < MAX_CLIENTS)
		{
			pthread_create(&th_id,NULL,interact,(void *)&sck);
			nb_clients++;
			printf("Nouveau client! %d clients\n",nb_clients);
		}
		else close(sck);
	}
	
	return 0;
}

 Conclusion

Voila je crois que le code n est pas trop complique a comprendre. Si vous avez des questions je serais bien sur ravis d y repondre! Et si vous avez des bugs a signaler, aussi!

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Sources du même auteur

Source avec Zip LECTURE/ECRITURE DES MSR (MODEL SPECIFIC REGISTER) EN C SOUS...
Source avec Zip Source avec une capture SOLUTION GRAPHIQUE APPROCHÉE AU PROBLÈME DES N CORPS
Source avec Zip TESTE SI UN TRES GRAND NOMBRE (PLUSIEURS MILLIERS DE CHIFFRE...
COMMENT UN PC FAIT DES MULTIPLICATIONS...
Source avec Zip COMPRESSION BZ2 (MIEUX QUE ZLIB) EN C.

 Sources de la même categorie

Source avec Zip TIM_RESEAU, CLASSES POUR RESEAU COMPLET par williamallas
Source avec Zip INTERNET IP FINDER TROUVER VOS ADRESSE IP (INTERNET) par xmustapha
Source avec Zip CLIENT/SERVEUR AVEC TSOCKETSERVER & TCLIENTSOCKET par xmustapha
Source avec Zip REMOTE SHELL GEN par ganjarasta
PROXY IRC SIMPLE (WINDOWS/WINSOCK) par _michel

Commentaires et avis

Commentaire de coucou747 le 28/08/2004 12:57:31

Mandrake 10.0 ?
Je croyais que xmms ne fonctionnait pas sur cet os ??? Bon, ça devait être spécifique a ma carte son lol...
Mais c'ets quoi ton pc pour survivre a 2 konqueror + xmms + 6 consoles dnas 1 terminal + un autre terminal + kwrite et tt ça dans un suel bureau .....? les 5 autres bureaux ont l'air d'être aussi pleins...
pas mal le système... j'ai esayé ton serveru sur un navigateur web... bon, ça marche pas, mais fallait s'y attendre, en telnet c'est parfait !
Se compile aussi bien sous mandrake 10.1


enfin voila j'ai mis 10/10

Commentaire de MetalDwarf le 28/08/2004 16:46:10

Oui ce serveur n est pas concu pour repondre au protocole IRC (trop complique!!) meme si ca doit etre faisable avec du temps...
et oui, mandrake 10.0 mais avec kernel et compilateur recompiles et mis a jour

Commentaire de coucou747 le 02/09/2004 21:21:17

j'eesayais de m'inspirer de ton code pour le faire sans threads... et j'ai aussi lu le linux mag 41...

j'ai croisé une étrange ressemblance entre les deux codes présentés, évidement, le tien a des threads que le code du linux mag n'a pas, mais c'est les mêmes noms de variables, parfois les mêmes lignes...

bon, je ne suis pas capable de reprendre un code de linux mag pour y ajouterdes threads, mais par contre le repater si...

D'ou viennent ces ressemblances ?

Commentaire de jon1012 le 03/09/2004 00:44:27

Salut, j'adore ton code (pris sur linux mag ou pas je m'en fiche lol, t'es un boss ;)) !
Par contre, je cherche comment envoyer une liste des clients connectés (je compte faire un client en gtk/c derriere ton serveur un peu modifié, si tu m'en donne l'autorisation bien sur !), si tu pouvais me mettre sur la piste ce serait génial, je n'y comprend pas grand chose en interactions entre threads et la maniere dont je peux trouver la liste de tous  les users connectés...
Enfin voilà...
Si tu veux, je pourrais poster ici le code modifié du serv pour aller avec mon client ainsi que mon client (qui normalement sera portable sous windows) :)

Voili voilà, donc bah si tu pouvai me donner ton autorisation de continuer ce que je fais :) (la license n'etant pas indiquée... si c'est du gpl, n'hésite pas à me le dire lol ;))
Voilà ! En tout cas, très bon code, bravo !

Jonathan

Commentaire de MetalDwarf le 03/09/2004 17:46:23

coucou47> He he oui le code de base des sockets reseaux est celui du Linux Magazine 41. En fait j avais recopie les fonctions create_server() et server_accept() au moment de la parution de ce Linux Magazine et depuis je fais un copier-coller de ces fonctions dans tous mes codes reseaux. Je precise quand meme que ce sont des fonctions de base qui se trouvent un peu partout (comme le fait remarquer l auteur de cet article dans un autre Linux Mag).
Sinon tout le code du serveur en lui meme est evidemment de moi, et en particulier la gestion des threads qui est le point que je voulais etudier en programmant ce serveur.

jom1012> Merci pour le code ca fait plaisir. Pour la liste des clients connectes c est tres simple, c est une commande qui est deja implementee dans le serveur. Si tu regarde bien c est la commande "/list". En fait toute les informations sur les clients sont contenus dans un tableau de pointeur sur une structure qui contient les infos sur le client, dont un champ pseudo (un char *) qui est le pseudo du client en question. Pour obtenir la liste des clients il suffit alors (cote serveur) de lire ces valeurs en parcourant le tableau (apres verrouillage de la structure par le mutex). Si tu veux rajouter des commandes c est tres simple. Il n y a qu une seule question a se poser : est ce que ma commande DOIT acceder (en lecture ou ecriture) au tableau des clients connectes? Si c est le cas il faut prendre le mutex AVANT de manipuler et le relacher APRES, en le gardant le moins de temps possible. D ailleurs le code peut etre ameliore en certains endroits car ceratines fonctions peuvent etre bloquantes sont appeles alors que le mutex est pris mais ce probleme n est pas tres grave. Si tu ne fais que toucher a me (la structure du client), il ne sert a rien de toucher au mutex.
Pour la realisation d un client en C/GTK je suis tout a fait pour, et je voulais le faire mais je ne connais pas le gtk et je n ai pas le temps pour me plonger dedant. Donc bien sur que tu as le droit de reprendre ce que j ai fait si tu mentionnes que le serveur original est de moi et que tu mets ce que tu as faut sur ce site.

Voila si tu as d autres questions je suis la pour y repondre.

Commentaire de coucou747 le 03/09/2004 19:53:43

bon, c'e"ts vrai que le code du linux mag n'était qu'une partie de carte par rapport au tien, je n'ai jamais voulu dire que ton travail était nul, j'ai d'ailleur souligné être dans l'incapacitée de faire ce genre de serveru, même avec le linuxmag... les threads je ne maitrises pas... et son code n'était pas mature... Tu es largement meilleur programmeur que moi, je n'ai jamais dis le contraire, mais tu aurais pu signaler le fait que ces deux fonctions apartiennent à qqn d'autre..

Sinon, j'ai un copain qui cherches a porter ce logiciel, on peut le faire comment pour qu'il fonctionne sous windows ? (quelle idée aussi de vouloir faire du windows réseau... ^^)

Commentaire de MetalDwarf le 03/09/2004 20:23:31

Oui c est vrai que j aurais pu le signaler... Et ce n est pas dur a programmer, les threads c est facile (la preuve, le code est simple), il faut seulement connaitre l API, et faire attention d eviter les corruptions eventuelles de donnees avec des mutex (ici c est simple il n y en a qu un seul, et pas de variable de condition). D ailleurs je ne connais pas trop les threads, c est mon premier code ou je les emploie!!

Pour porter ce code sous windows, il y acdeux problemes : les socket et les threads. Les sockets ce n est pas trop un probleme, en modifiant les fonctions create_server() et server_accept() ca passe sans probleme (et en rajoutant un appel a la fonction d initialisation des sockets windows). Par contre pour les threads l API utilisee ici est celle des threads POSIX (donc *hautement* portable), mais windows a sa propre API, et je ne sais pas comment adapter (bien sur les mutex existent aussi sous windows mais l API differe). Le mieux est d aller voir sur MSDN je pense, et peut etre que microsoft offre une compatibilite avec l API POSIX (j espere...).

Commentaire de FearBlue le 13/09/2004 19:55:03

slt a tous
je susi sous MANDRAKE 10.0
et g l'erreur suivante lors de la compilation

[florian@athlon serveur chat]$ g++ server_flo.c -o server2
/home/florian/tmp/cck6idJN.o(.text+0xe40): In function `main':
: undefined reference to `pthread_create'
collect2: ld returned 1 exit status
[florian@athlon serveur chat]$ g++ server_flo.c -o server2
/home/florian/tmp/cceCSeu4.o(.text+0xc78): In function `interact(void*)':
: undefined reference to `pthread_cancel'
/home/florian/tmp/cceCSeu4.o(.text+0xe52): In function `main':
: undefined reference to `pthread_create'
collect2: ld returned 1 exit status

g essayer avec Gcc et c pareil
si vous savez ???

Commentaire de coucou747 le 13/09/2004 19:58:11

si tu lis la première ligne de la source, t'as la ligne de code a passer au compilo... et bizarement, comme ce programem est en C etpas en C++, on utilises gcc et pas C++

Moi je l'ai pas testé sous mandrake 10.0 mais 10.1, et si tu regardes la copie d'écran, tu devrais voir rapidement que metaldwarf est sous le même os que toi

Commentaire de MetalDwarf le 13/09/2004 20:41:35

Non c est pas la qu est le probleme. Le probleme c est que la source utilise la bibliotheque pthread, (qui est presente sur tous les systemes), et donc il faut preciser l option -lpthread a gcc ou g++. Ca devrait quand meme passer avec g++, mais c est du C, donc gcc!!

Commentaire de coucou747 le 13/09/2004 21:26:32

c'est ce que j'ai dit, t'as ces options tt au début de ta source en commentaire, faut pasque compiler, faut lire aussi ^^

Commentaire de FearBlue le 13/09/2004 22:05:47

oki merci les gars ca marche nikel
merci bcp
++ et bonn prog's

Commentaire de blade_m le 28/10/2004 09:10:15

Petite question, aurais tu le client qui va avec le serveur?

Merci

Commentaire de coucou747 le 28/10/2004 09:31:50

telnet marche très bien, sinon tu peux en écrire un (regardes la caprure d'écran, c'etstrsè joli KDE)

Commentaire de blade_m le 28/10/2004 13:16:59

car j'ai un projet pour mes études:

faire un client/serveur avec forum, administration, chat...


Merci

Commentaire de coucou747 le 28/10/2004 13:19:02

dans ce cas je teproposes d'adapter ce serveur au languge http, et t'auras pas a programmer le client, t'auras Mozilla ou Ie pour ça.

Commentaire de MetalDwarf le 28/10/2004 15:58:36

Incroyable, coucou47 repond plus vite que moi aux commentaire sur ma source!!

Si tu veux etendre ce serveur, ca doit se faire sans trop de mal, d utant plus qu il ne manque presque rien pour faire de ce serveur un module integrable independamment du reste.
Si tu doit faire un client/serveur comme ca, tu peux batir une interface graphique sur un client tout simple, je pense que si tu connais la programmation graphique ca ne devrait pas etre trop long. Par contre pour faire un forum, il va falloir aller chercher ailleurs, car si tu veux modifier ce serveur pour ca il va falloir mettre beaucoup de choses en plus. Le plus simple dans ce cas est peut etre d utiliser le protocole HTTP et d'integrer php a ton serveuir (ce qui se fait tres facilement sous Unix, il suffit de recuperer la sortie de la page php passee au programme php).

Commentaire de blade_m le 29/10/2004 10:11:11

Merci

Mais je dois faire ce projet sous linux en mode console, donc pas d'interface graphique!
aue des lignes de commandes

Commentaire de coucou747 le 29/10/2004 10:17:58

forum mode console...

Commentaire de MetalDwarf le 29/10/2004 11:00:32

Dans ce cas, recuperer ce serveur peut etre utile!!
Pour ecrire un client, c es vraiment pas dur il suffit de creer 2 threads (un pour lire l entree et un pour recevoir ce que dit le serveur), ou alors d utiliser select(). Le petit probleme c est que si un message arrive pendant que tu es en train d ecrire kkchose, ca va couper en 2 ce que tu ecris. Tu peux alors soit utiliser des entrees/sorties bloquantes (donc ne pas utiliser select() ni de threads), ou alors chercher dans la doc de ncurses (librairie permettant d avoir une interface "graphique" en mode console... enfin comme emacs a peu pres ou edit sous DOS...) si tu ne peux pas faire ca autrement.

Commentaire de blade_m le 29/10/2004 21:09:54

Merci bcp, je vais essayer ca!

Commentaire de chermy le 18/04/2006 16:08:52

j'aimerai savoir comment fait on pour avoir le client socket pour se connecter au serveur
merci d'avance

Commentaire de cyrtex le 21/06/2006 14:53:49


Pour ceux que ça interesse, voici un client ligne de commande  fonctionnant avec ce serveur de chat:

http://globnet.free.fr/include/m1-client.exe

Il s'agit d'un "simple" programme telnet adapté pour faire en sorte que les messages arrivant ne viennent pas perturber la saisie d'un message en cours.

Commentaire de facilus le 05/11/2006 00:28:51

j'ai lancé le source sous linux ,avec la commande " ./server " , mais je ne sais pas ce k'il faus faire par la suite , est ce ke je doit ecrire un autre programme pour ke le chatr fonctionne ???
merci de m'indiquer comment faire marchee ce source client /serveur

Commentaire de coucou747 le 06/11/2006 08:50:31

G 1 truK bi1 pr ke tu puiS nou liR...

On va tous parler corectement ok ? sinon, ça risque de devennir totalement illisible...

tu tapes :
user@linux$ telnet host port
dans une console linux

Moi j'ajoute un message pour remercier MetalDwarf, je lui dois mon augmentation de niveau depuis ces trois dèrnières années...

Commentaire de oazize le 25/09/2007 13:13:50

Code super propre!! merci c'est génial

Je digere le code et j'essairai de faire un client en flash.

Merci encore

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix


HTC Hero

Entre 550€ et 550€

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,952 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales