chating UDP en C

Chating par UDP:

Utilitaire

#include "soct.h" 

/*Ecriture sur une socket */
/*
	$Id: wrsock.c,v 2.4 2000/07/06 09:53:04 pfares Exp $ 
	$Log: wrsock.c,v $
	Revision 2.4  2000/07/06 09:53:04  pfares
	commentaires

	Revision 2.3  2000/07/05 21:35:02  root
	commentaires pour le cours reseau B.

	Revision 2.2  2000/07/05 21:09:21  root
	Avant de demarrer test de ci co cvs

 * Revision 1.2  1997/03/22  06:40:48  pascal
 * Ajout de commentaires
 *
 * Revision 1.1  1997/03/22  06:26:10  pascal
 * Initial revision
 * */

/******************************************************************/
/* writes : Fonction pour l'exriture en mode connecte sur un stream*/
/* INPUT:	                                                      */
/*    IN sock : identifiant d'E/S fid                             */
/*    IN pbuf : Le buffer utiliser pour l'écriture                */
/*    IN noc : Le nobre d'actets à transmettre                    */
/* OUTPUT                                                         */
/*    OUT : Le nombre d'octets rééllement envoyés ou une erreur (<0)*/
/* Description:                                                   */
/*    Dans certains cas la primitive système write n'envoie pas   */
/*    tous les actets demandés (elle retourne le nombre d'octets  */
/*    rééllement emis). On relance alors l'émisson jusqua épuisement */
/*    de tous les actets que l'on souhaite émettre                 */
/* Alogirithme:                                                    */
/*    tanque il reste des octets à emettre                         */
/*        Emmetre les octets restants                              */
/******************************************************************/
int writes(int sock, char *pbuf, int noc)
{
	int nreste, /* nombre d'octats restant à emmetre */ 
	    necrit; /* Variable qui contiendra le nb d'octets rééllement émis par write */

	/* Initialement le nb d'octets restant a éméttre est noc */	
	nreste = noc;
	while(nreste > 0)
	{ 
		necrit = write(sock, pbuf, nreste);
		/* si necrit < 0 alors pb */
		if (necrit < 0) return (necrit);
		nreste -= necrit;
		pbuf += necrit;
	}
	return(noc-nreste);
}

/******************************************************************/
/* Fonction pour la lecture en mode connecte                      */
/******************************************************************/
int reads(int sock, char *pbuf, int noc)
{
	int nreste, nlit;
	
	nreste = noc;
	while(nreste > 0)
	{ 
		nlit = read(sock, pbuf, nreste);
		if (nlit < 0) return (nlit);
		nreste -= nlit;
		pbuf += nlit;
	}
	return(noc-nreste);
}
/**/
/*****************************************************************/
/* Fonction pour la creation d'une adresse (service) pour la     */
/* Communication par socket                                      */
/*                                                               */
/* Entree : name : nom de la machine                              */
/*          port : numero de port pour le service                */
/* Sortie :                                                      */
/*         La fonction retourne (et alloue) un objet de type    */
/*                  struct sockaddr_in (internet adresse)       */
/*****************************************************************/
   

struct sockaddr_in *CreerSockAddr(char *name, int port) {
  struct sockaddr_in *adsock =(struct sockaddr_in *) 
    malloc(sizeof(struct sockaddr_in));

  struct hostent *haddr=NULL;
  struct in_addr **pptr;
  char str[32];
#ifdef DEBUG
  printf("IN CreerSockAddr %s,%d\n", name, port);
#endif
  bzero(adsock, sizeof(adsock));
  if (name) {
    haddr = gethostbyname(name);
    if (haddr <= 0) {
      perror("Nom de machine inconnu");
    }
    else {
      pptr = (struct in_addr **) haddr->h_addr_list;
      memcpy(&adsock->sin_addr, *pptr, sizeof(struct in_addr));
      inet_ntop(haddr->h_addrtype, *pptr, str, sizeof(str));
#ifdef DEBUG      
      printf("%s", str);
#endif
    }
  }
  else {
    adsock->sin_addr.s_addr=INADDR_ANY;
  }

  adsock->sin_family=AF_INET;
  adsock->sin_port = htons(port);
#ifdef DEBUG
  printf("fin\n");
#endif
    return (adsock);
}

/* ======================================================================
 * Creation d'une socket serveur UDP en l'associant au service definit 
 * Par numport                                                 
 * INPUT:
 *  IN nom : nom DNS de l'adresse
 *  IN numport : le numéro de port pour l'écoute UDP
 * ======================================================================
 */
	
int SockUdp(char *nom, int numport) {
  int sock;
  int r=1;
  /* adsock : adresse de la socket d'écoute */
  struct sockaddr_in *adsock = (struct sockaddr_in *) 
    CreerSockAddr(nom, numport);

  if ((sock=socket(AF_INET,SOCK_DGRAM,0)) <= 0) {
    perror("\n pb creation socket \n");
  }
  /*	sock=dup(sock);
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &r, sizeof(r));
  */
#ifdef DEBUG
  printf("La socket num %d\n", sock);
#endif
  if (bind(sock,(struct sockaddr *) adsock, sizeof(*adsock)) <0) {
		perror("\n pb bind");
  }
  return(sock);
}

#include "soct.h"

/* $Id: client.c,v 1.2 2000/07/06 09:51:59 pfares Exp $
 * $Log: client.c,v $
 * Revision 1.2  2000/07/06 09:51:59  pfares
 * Amélioration du protocole entre client et serveur (recupération du
 * port client par recvfrom
 *
 * Revision 1.1  2000/07/05 20:51:16  root
 * Initial revision
 *
 */

/* L'adresse du serveur et port 
 */
struct sockaddr_in *autre;

int len = sizeof (struct sockaddr_in);

/*
 * TraitementClavier : Lit la console (fd = 0) et transmet la chaine lu au serveur
 * ===============
 *
 * Entree : sock : la socket d'Etree/Sortie
 * Sortie  : void
 *
 * Remarque : 
 */
void 
TraitementClavier (int sock)	/* Socket E/S */
{
  char buf[256];
  int taillemessage;
  int i;


  taillemessage = read(0, buf, 256);
  /* Envoyer a tous les client la taille du message puis le message */
  sendto (sock, &taillemessage, sizeof (taillemessage), 0,
	  (struct sockaddr *) autre, sizeof (struct sockaddr));

  sendto (sock, buf, taillemessage, 0,
	  (struct sockaddr *) autre, sizeof (struct sockaddr));

}

/*
 * TraitementSock  : Traitement de l'arrive d'information sur la socket
 * =============
 *
 * Entree : Sock : La socket d'E/S
 * Sortie  : void
 *
 * PSeudoCode :
 * ----------
 * Debut
 *     Lire taillemessage sur la socket d'entree en provenance du serveur 
 *     Lire message 
 *     Afficher le message a l'ecran
 * Fin
 *
 * Remarques:
 * L'adresse du serveur est definie par la variable globale autre
 */
void 
TraitementSock (int sock) {
  char buf[256];        /* Buffer de reception
			 */
  
  int  taillemessage;   /* Taille du message a recevoir
			 * Chaque emetteur commence par envoyer la taille du
			 * message
			 */
  
  /* On recoit la taile du message puis le message 
     */
  recvfrom (sock, &taillemessage, sizeof (taillemessage), 0,
	    (struct sockaddr *) NULL, NULL);

  recvfrom (sock, buf, taillemessage, 0,
	    (struct sockaddr *) NULL, NULL);

  /* Ecriture du message recu a l'ecran
   */
  write (1, buf, taillemessage);
}

/*
 * Un client possede un numero : qu'il lit dans argv                   
 * ce numero est envoyer au serveur qui l'tilisera pour repondre        
 */

main (int argc, char **argv) {
  int sockrec;      /* Socket d'emission reception */

  fd_set readf;     /* L'ensemble de descripteur en lecture a utilise avec select */
  int num;

  if (argc != 3) {
    printf("Utilisation :  \n");
    exit(1);
  }
  num = atoi (argv[2]); /* L'identifiant client : donné par l'utilisateur */

#ifdef DEBUG
  printf ("\n : Info : Client numero => %d \n", num);
#endif
  /*Creartion de la socket du client 2000+numero client */
  sockrec = SockUdp (NULL, 2000 + num);

  /* autre adresse du serveur de chating */
  autre = (struct sockaddr_in *) CreerSockAddr (argv[1], 2001);

  /* utilisation du select pour attendre une lecture de plusieurs entrés
   */
  for (;;) {
    FD_SET (sockrec, &readf);
    FD_SET (0, &readf);
    
    switch (select (sockrec + 1, &readf, 0, 0, 0)) {
    default:
      if (FD_ISSET (0, &readf)){
	TraitementClavier (sockrec);
      }
      else if (FD_ISSET (sockrec, &readf)) {
	TraitementSock (sockrec);
      }
    } /*switch*/
  }/*for*/
}/*main*/
#include "soct.h"
/*
	$Id: serveur.c,v 1.2 2000/07/06 09:52:41 pfares Exp $
	$Log: serveur.c,v $
	Revision 1.2  2000/07/06 09:52:41  pfares
	 Amélioration du protocole entre client et serveur (recupération du
	 port client par recvfrom
	 .

	Revision 1.1  2000/07/05 20:52:04  root
	Initial revision

 * Revision 1.2  1997/03/22  06:15:04  pascal
 * Ajout des controles et entete
 *
*/
struct sockaddr_in *autre[100]; /* Table des clients qui ont contacte
                                    le serveur */
int len = sizeof(struct sockaddr_in);
 
void TraitementClavier(int sock) { /* Socket E/S */
  char buf[256];
  int taillemessage;
  int  i;
         
  taillemessage=read(0, buf, 256);               
  for (i=0; i< 100; i++)
    if (autre[i]) { /* Si un client est enregistre */
      /* Envoyer a tous les client la taille du message puis le message */
      sendto(sock,&taillemessage, sizeof(taillemessage), 0,
	     (struct sockaddr *)autre[i], sizeof(struct sockaddr));
      
      sendto(sock,buf, taillemessage, 0, 
	     (struct sockaddr *)autre[i], sizeof(struct sockaddr));
    }  
  
}                         

/*
 * Traitement de reception sur la socket du serveur
 * On recipere dans l'ordre
 * 	=> Le numero du client
 *	=> La taille du message
 * Le message est alors trace a l'ecran (pour controle)
 * et enfin il est redistribué atous les clients connus
 *
 * Entree: sock : la socket d'ecoute
 * Sortie : NEANT
 */ 
void TraitementSock(int sock) {
  char buf[256];
  int numappelant;
  int taillemessage;
  int i;
  int len;
  struct sockaddr_in *appellant= (struct sockaddr_in *) 
    malloc(sizeof(struct sockaddr_in));;
  /* Le client commance par envoyer la taille du message : que le serveur recupere */
  /* On recupère aussi dans appellant l'adresse du client */
  recvfrom(sock, &taillemessage, sizeof(taillemessage), 0, 
	   (struct sockaddr *) appellant, &len);

  numappelant=ntohs(appellant->sin_port)-2000;
#ifdef DEBUG
  printf("port appelant = %d\n", numappelant);
#endif

  /* Si c'est la premiere fois le client est enregistre 
   */
  if (autre[numappelant] == NULL) {
    autre[numappelant] = appellant;
  }    
  
  /* Quant toutes les information sont récupéré (l'adresse client et la taille du message)
   * On recupère le message proprement dit
   */
  recvfrom(sock, buf,  taillemessage, 0, 
	   (struct sockaddr *) NULL, NULL);

  write(1,buf, taillemessage);

  for (i=0; i< 100; i++)
    if (autre[i]) {
      /* Envoyer a tous les client la taille du message puis le message */
      sendto(sock,&taillemessage, sizeof(taillemessage), 0,
	     (struct sockaddr *)autre[i], sizeof(struct sockaddr));
      sendto(sock,buf, taillemessage, 0, 
	     (struct sockaddr *)autre[i], sizeof(struct sockaddr));
    }
  
}


/*
 * 
 */

main () {
  int 	sockrec;  /* Socket de reception / Emission    */
  fd_set 	readf;    /* L'esemble de descripteur d'entree */
  int 	i;
  
  
  /* Initialisation des client (au depart aucun)
   * Il faut amélioré (par liste chaînée ou autre (ne pas mettre 100 ici)
   */
  for (i=0; i< 100; i++) autre[i] = NULL; 
  
  /* Le service du serveur est le 2001
   */
  sockrec = SockUdp(NULL, 2001);
  
  /*
   *     autre = (struct sockaddr_in *) CreerSockAddr("ghadir", 2001);
   */
  for(;;) {
    FD_SET(sockrec, &readf);
    FD_SET(0, &readf);
    
    switch (select (sockrec+1, &readf, 0,0,0)) {
    default :
      if (FD_ISSET(0, &readf)) {          /* STDIN*/
	
	TraitementClavier(sockrec);  
      }
      else if (FD_ISSET(sockrec, &readf)) {/*SOCKET*/
	    
	TraitementSock(sockrec);
      }
      
    }
  }
}	


Comments